diff --git a/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_benchmark.xml b/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_benchmark.xml
index 89b9cc7dc86..adbf453fa25 100644
--- a/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_benchmark.xml
+++ b/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_benchmark.xml
@@ -1,294 +1,397 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ 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..322444e025d 100644
--- a/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_smoke.xml
+++ b/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_smoke.xml
@@ -1,294 +1,391 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ 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..01804189fd8 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"
+ useMass="1">
+
+
+
+
-
+
-
+
+ name="fluidTPFA"/>
@@ -80,13 +84,16 @@
solidModelName="nullSolid"
porosityModelName="rockPorosity"
permeabilityModelName="rockPerm"/>
+
+
+
@@ -94,9 +101,8 @@
-
+ wettingNonWettingRelPermTableNames="{ waterRelativePermeabilityTable, gasRelativePermeabilityTable }"/>
+
-
-
-
+
+
+
+
-
@@ -152,11 +158,13 @@
name="initCO2CompFracTable"
coordinates="{ -3238.2, -2506.13 }"
values="{ 0.000001, 0.000001 }"/>
+
-
@@ -165,37 +173,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..fe5f4272ad2 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="massRate"
+ useMass="1">
+
+
+
+
-
-
-
+
+ name="fluidTPFA"/>
-
-
-
+
+
+
-
-
-
+ wettingNonWettingRelPermTableNames="{ waterRelativePermeabilityTable, gasRelativePermeabilityTable }"/>
-
-
-
-
-
-
-
-
+
+
+
-
@@ -204,11 +202,13 @@
name="initCO2CompFracTable"
coordinates="{ -3238.2, -2506.13 }"
values="{ 0.000001, 0.000001 }"/>
+
-
@@ -217,43 +217,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..01e328f6cfa 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"
+ useMass="1">
+
+
+
+
-
+
-
+
+ name="fluidTPFA"/>
@@ -80,26 +84,27 @@
solidModelName="nullSolid"
porosityModelName="rockPorosity"
permeabilityModelName="rockPerm"/>
+
+
+
-
-
+
-
-
-
-
-
+
+
+
+
-
@@ -157,59 +160,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..b71cf698726 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"
+ useMass="1">
+
+
+
+
-
+
-
+
+ name="fluidTPFA"/>
@@ -84,28 +88,27 @@
solidModelName="nullSolid"
porosityModelName="rockPorosity"
permeabilityModelName="rockPerm"/>
+
+
+
-
-
-
-
+
-
-
+
+
+
+
-
@@ -161,10 +164,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..40d16d1a47a 100644
--- a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_direct.xml
+++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_direct.xml
@@ -1,7 +1,6 @@
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+ maxCompFractionChange="0.5"
+ useMass="1">
+
+
+
+
-
-
-
-
-
-
-
-
@@ -279,7 +350,6 @@
materialList="{ fluid }"/>
-
-
-
-
-
@@ -373,32 +439,27 @@
-
-
-
+ fieldName="wellElementConnectionRate"/>
+ fieldName="wellElementConnectionRate"/>
+ fieldName="wellElementConnectionRate"/>
+ fieldName="wellElementConnectionRate"/>
-
-
diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_iterative.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_iterative.xml
index 615688bef78..3922880cf1a 100644
--- a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_iterative.xml
+++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_iterative.xml
@@ -1,7 +1,6 @@
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+ maxCompFractionChange="0.5"
+ useMass="1">
+
+
+
+
-
-
-
-
-
-
-
-
@@ -281,7 +352,6 @@
materialList="{ fluid }"/>
-
-
-
-
-
@@ -375,32 +441,27 @@
-
-
-
+ fieldName="wellElementConnectionRate"/>
+ fieldName="wellElementonnectionRate"/>
+ fieldName="wellElementConnectionRate"/>
+ fieldName="wellElementConnectionRate"/>
-
-
diff --git a/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d.xml b/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d.xml
index 7ebac080cbc..dba3b84b0c5 100644
--- a/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d.xml
+++ b/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d.xml
@@ -2,7 +2,6 @@
-
-
+
-
-
-
+
+
+
+
-
+ maxRelativePressureChange="0.1"
+ maxCompFractionChange="0.1"
+ useMass="1">
+
+
+
+
-
-
-
-
+
-
+
-
+
-
@@ -148,12 +157,14 @@
name="region"
cellBlocks="{ * }"
materialList="{ fluid, rock, relperm, cappres }"/>
+
+
+ materialList="{ fluid }"/>
@@ -163,7 +174,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 }"/>
-
+
-
+
+ fieldName="wellElementConnectionRate"/>
-
+
-
+
-
diff --git a/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d_stone2.xml b/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d_stone2.xml
index ce669961545..a285a0d9773 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 @@
-
-
+
-
-
-
+
+
+
+
-
+ maxRelativePressureChange="0.1"
+ maxCompFractionChange="0.1"
+ useMass="1">
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
-
+
-
+
-
@@ -147,12 +157,14 @@
name="region"
cellBlocks="{ * }"
materialList="{ fluid, rock, relperm, cappres }"/>
+
+
+ materialList="{ fluid }"/>
@@ -162,7 +174,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 }"/>
-
+
-
+
+ fieldName="wellElementConnectionRate"/>
-
+
-
+
-
diff --git a/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d.xml b/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d.xml
index 323b9a144c6..d2b7a5cd375 100644
--- a/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d.xml
+++ b/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d.xml
@@ -2,7 +2,6 @@
-
-
+
-
-
-
+
+
+
+
-
+ maxRelativePressureChange="0.1"
+ maxCompFractionChange="0.1"
+ useMass="1">
+
+
+
+
-
-
-
-
-
+
-
-
+
-
+
-
@@ -148,12 +158,14 @@
name="region"
cellBlocks="{ * }"
materialList="{ fluid, rock, relperm }"/>
+
+
+ materialList="{ fluid }"/>
@@ -163,7 +175,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"/>
+
-
+
-
+
+ fieldName="wellElementConnectionRate"/>
-
+ 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..297511e60ae 100644
--- a/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d_stone2.xml
+++ b/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d_stone2.xml
@@ -1,260 +1,271 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/compositionalMultiphaseWell/bos.xml b/inputFiles/compositionalMultiphaseWell/bos.xml
new file mode 100644
index 00000000000..75b5a9826ad
--- /dev/null
+++ b/inputFiles/compositionalMultiphaseWell/bos.xml
@@ -0,0 +1,307 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/compositionalMultiphaseWell/compositional_multiphase_wells_1d.xml b/inputFiles/compositionalMultiphaseWell/compositional_multiphase_wells_1d.xml
index bea2c48815d..0869a727917 100644
--- a/inputFiles/compositionalMultiphaseWell/compositional_multiphase_wells_1d.xml
+++ b/inputFiles/compositionalMultiphaseWell/compositional_multiphase_wells_1d.xml
@@ -23,28 +23,38 @@
targetRegions="{ Region1 }"
temperature="297.15"/>
-
-
-
+
+
+
+
-
+ control="totalVolRate">
+
+
+
+
@@ -58,7 +68,6 @@
ny="{ 1 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
+ name="fluidTPFA"/>
@@ -175,7 +182,6 @@
-
-
-
-
-
-
+
+
+
+
-
+
+
+
+
-
-
-
+ control="totalVolRate">
+
+
+
+
@@ -69,7 +81,6 @@
ny="{ 20 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
+ name="fluidTPFA"/>
@@ -223,7 +231,6 @@
-
-
-
-
+
-
+
+
+
+
-
+
+
+
+
-
+ control="totalVolRate"
+ maxRelativePressureChange="0.1"
+ maxCompFractionChange="0.1">
+
+
+
+
@@ -78,7 +97,6 @@
ny="{ 20 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
+ name="fluidTPFA"/>
@@ -223,7 +238,6 @@
-
-
-
-
+
-
-
+
-
+
+
+
+
-
+
+
+
+
-
+ control="totalVolRate"
+ maxRelativePressureChange="0.1"
+ maxCompFractionChange="0.1">
+
+
+
+
@@ -77,7 +96,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..d69956ea1de 100644
--- a/inputFiles/compositionalMultiphaseWell/dome_soreide_whitson_base.xml
+++ b/inputFiles/compositionalMultiphaseWell/dome_soreide_whitson_base.xml
@@ -1,287 +1,348 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/compositionalMultiphaseWell/isothm_mass_inj_table.xml b/inputFiles/compositionalMultiphaseWell/isothm_mass_inj_table.xml
index 14076fab917..9ecff209034 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"
+ useMass="1">
+
+
+
+
@@ -83,10 +86,8 @@
-
-
@@ -94,8 +95,6 @@
name="sink"
xMin="{ 89.99, 89.99, -0.01 }"
xMax="{ 101.01, 101.01, 1.01 }"/>
-
-
-
-
@@ -143,25 +143,28 @@
name="region"
cellBlocks="{ cb }"
materialList="{ fluid, rock, relperm }"/>
+
-
+
+
+
@@ -181,11 +184,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..1e191175e19 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"
+ useMass="1">
+
+
+
+
@@ -82,10 +86,8 @@
-
-
@@ -93,8 +95,6 @@
name="sink"
xMin="{ 89.99, 89.99, -0.01 }"
xMax="{ 101.01, 101.01, 1.01 }"/>
-
-
-
-
-
@@ -148,25 +150,28 @@
name="region"
cellBlocks="{ cb }"
materialList="{ fluid, rock, relperm }"/>
+
-
+
+
+
@@ -186,11 +191,9 @@
phaseMinVolumeFraction="{ 0.0, 0.0 }"
phaseRelPermExponent="{ 1.5, 1.5 }"
phaseRelPermMaxValue="{ 0.9, 0.9 }"/>
-
-
+
+
+
-
diff --git a/inputFiles/compositionalMultiphaseWell/resvol_constraint.xml b/inputFiles/compositionalMultiphaseWell/resvol_constraint.xml
index 7fe917a2076..134b8a44552 100644
--- a/inputFiles/compositionalMultiphaseWell/resvol_constraint.xml
+++ b/inputFiles/compositionalMultiphaseWell/resvol_constraint.xml
@@ -23,31 +23,42 @@
targetRegions="{ Region1 }"
temperature="297.15"/>
-
-
-
+
+
+
+
-
+ writeCSV="1">
+
+
+
+
@@ -61,7 +72,6 @@
ny="{ 1 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
+
-
-
+
+ name="fluidTPFA"/>
@@ -192,7 +201,6 @@
-
-
-
-
-
-
-
+ useSurfaceConditions="1"
+ surfacePressure="101325"
+ surfaceTemperature="288.71"
+ control="totalVolRate"
+ maxCompFractionChange="0.2"
+ useMass="1">
+
+
+
+
-
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
@@ -185,42 +178,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..d6359b2765e 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..db9b88c034e 100644
--- a/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_3d.xml
+++ b/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_3d.xml
@@ -25,36 +25,47 @@
maxCompFractionChange="0.2"
useMass="1"/>
-
-
-
+
+
+
+
-
+ maxCompFractionChange="0.2"
+ useMass="1">
+
+
+
+
-
-
-
+ 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 +226,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..3f398adb118 100644
--- a/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_hybrid_3d.xml
+++ b/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_hybrid_3d.xml
@@ -28,35 +28,48 @@
maxRelativePressureChange="0.2"
useMass="1"/>
-
-
-
+
+
+
+
-
+ maxRelativePressureChange="0.2"
+ maxCompFractionChange="0.2"
+ useMass="1">
+
+
+
+
-
-
-
-
+
diff --git a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim.xml b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim.xml
index 0ca07929f8e..77dfa798145 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 }"/>
-
-
-
+
+
+
+
-
-
+ control="totalVolRate"
+ maxCompFractionChange="0.2"
+ useMass="1">
+
+
+
+
-
+
+
-
+
+
-
+
-
-
-
diff --git a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential.xml b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential.xml
index e978595a49f..4cebe6d253e 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 }"/>
-
-
-
+
+
+
+
-
-
+ control="totalVolRate"
+ maxCompFractionChange="0.2"
+ useMass="1">
+
+
+
+
-
+
+
-
+
+
-
+
-
-
diff --git a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim.xml b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim.xml
index 95f2090ada1..ad32b0c1f53 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 }"/>
-
-
-
+
+
+
+
-
-
+ 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..838f662c5a9 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 }"/>
-
-
-
+
+
+
+
-
-
+ surfacePressure="101325"
+ control="totalVolRate">
+
+
+
+
-
+ minTime="-1e11"
+ maxTime="1e7">
-
+
+
-
+
-
@@ -118,24 +125,25 @@
name="linearElasticityStatistics"
solidSolverName="linearElasticity"
logLevel="1"/>
+
-
-
+
+
-
diff --git a/inputFiles/poromechanics/ReservoirThermoPoroElastic_Circulation_debug.xml b/inputFiles/poromechanics/ReservoirThermoPoroElastic_Circulation_debug.xml
index b2a0d65d59d..feb3d2e9307 100644
--- a/inputFiles/poromechanics/ReservoirThermoPoroElastic_Circulation_debug.xml
+++ b/inputFiles/poromechanics/ReservoirThermoPoroElastic_Circulation_debug.xml
@@ -2,12 +2,12 @@
-
+
-
-
-
-
+
+
+
+
-
-
+ writeCSV="1">
+
+
+
+
+
-
-
+
+
@@ -162,7 +173,6 @@
-
-
+ targetTime="-1e10"/>
-
+
-
-
-
+ poromechanicsSolverName="reservoirPoromechanics"/>
-
diff --git a/inputFiles/poromechanicsFractures/multiphasePoromechanics_FaultModel_well_fim_smoke.xml b/inputFiles/poromechanicsFractures/multiphasePoromechanics_FaultModel_well_fim_smoke.xml
index 0ce10628d75..56de13ffa2b 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"
+ useMass="1"
+ writeCSV="1">
+
+
+
+
@@ -88,47 +96,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..4a30e02941e 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"
+ useMass="1"
+ writeCSV="1">
+
+
+
+
@@ -97,47 +105,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..72aad6f89b6 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">
+
+
+
+
-
+
+
-
-
-
+
-
+
-
+ solverType="direct"/>
+ targetRegions="{ Region, Fault }"
+ discretization="FE1"/>
-
+ targetRegions="{ Region, Fault }"/>
-
-
-
+
+
+
+
-
+ control="BHP">
+
+
+
+
-
+
+
-
-
-
+
-
+
-
+ directParallel="1"/>
-
+ logLevel="1"/>
+ targetRegions="{ Region, Fault }"
+ discretization="FE1"/>
-
+ targetRegions="{ Region, Fault }"/>
-
-
-
+
+
+
+
-
+ logLevel="2"
+ writeCSV="1"
+ type="injector">
+
+
+
+
-
+
+
-
-
-
+
-
+
-
+ directParallel="1"/>
+ targetRegions="{ Region, Fault }"
+ discretization="FE1"/>
-
+ targetRegions="{ Region, Fault }"/>
-
-
-
+
+
+
+
-
+ logLevel="2"
+ writeCSV="1"
+ 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..0fe903b3199 100644
--- a/inputFiles/singlePhaseWell/compressible_single_phase_wells_1d.xml
+++ b/inputFiles/singlePhaseWell/compressible_single_phase_wells_1d.xml
@@ -20,25 +20,35 @@
discretization="singlePhaseTPFA"
targetRegions="{ Region1 }"/>
-
-
-
+
+
+
+
-
+ control="totalVolRate">
+
+
+
+
@@ -52,7 +62,6 @@
ny="{ 1 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
-
-
+
+
+
+
-
+ control="totalVolRate">
+
+
+
+
@@ -52,7 +62,6 @@
ny="{ 1 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
+ distanceFromHead="1.45"
+ skinFactor="1"/>
-
-
-
+
-
+
+
+
+
-
+ control="totalVolRate">
+
+
+
+
@@ -53,7 +63,6 @@
ny="{ 1 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
-
+
-
+
+
+
+
-
+
+
+
+
-
+ 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..28a95e82f30 100644
--- a/inputFiles/singlePhaseWell/incompressible_single_phase_wells_hybrid_2d.xml
+++ b/inputFiles/singlePhaseWell/incompressible_single_phase_wells_hybrid_2d.xml
@@ -21,32 +21,47 @@
discretization="singlePhaseHybridMimetic"
targetRegions="{ Region1 }"/>
-
-
-
+
+
+
+
-
+
+
+
+
-
+ control="totalVolRate">
+
+
+
+
@@ -60,7 +75,6 @@
ny="{ 20 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
-
-
+
-
+
+
+
+
-
+
+
+
+
-
+ 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..55da1048afe 100644
--- a/inputFiles/singlePhaseWell/staircase_single_phase_wells_3d.xml
+++ b/inputFiles/singlePhaseWell/staircase_single_phase_wells_3d.xml
@@ -16,29 +16,39 @@
-
-
-
+
+
+
+
-
+ 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..256250d8cc7 100644
--- a/inputFiles/singlePhaseWell/staircase_single_phase_wells_hybrid_3d.xml
+++ b/inputFiles/singlePhaseWell/staircase_single_phase_wells_hybrid_3d.xml
@@ -21,27 +21,37 @@
discretization="singlePhaseHybridMimetic"
targetRegions="{ Channel }"/>
-
-
-
+
+
+
+
-
+ 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..d7bf9d12087 100644
--- a/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp
@@ -94,26 +94,31 @@ char const * xmlInput =
targetRegions="{ region }">
-
-
+ surfaceTemperature="300.15">
+
+
+
@@ -300,7 +305,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio
real64 const relTol,
LAMBDA && assembleFunction )
{
- CompositionalMultiphaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() );
localIndex const NC = flowSolver.numFluidComponents();
@@ -463,7 +468,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio
wellElemCompDens.move( hostMemorySpace, false );
arrayView1d< real64 > const & connRate =
- subRegion.getField< fields::well::mixtureConnectionRate >();
+ subRegion.getField< fields::well::connectionRate >();
connRate.move( hostMemorySpace, false );
// a) compute all the derivatives wrt to the pressure in WELL elem iwelem
@@ -580,6 +585,23 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( time, dt, domain );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.initializeWell( domain, meshLevel, subRegion, time );
+ } );
+ } );
}
static real64 constexpr time = 0.0;
@@ -641,7 +663,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellAccumulationTerms( time, dt, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
diff --git a/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp
index 277c7a2a38c..0023ec39654 100644
--- a/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp
@@ -94,26 +94,31 @@ char const * xmlInput =
targetRegions="{ region }">
-
-
-
+ surfaceTemperature="300.15">
+
+
+
+
@@ -301,7 +306,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio
real64 const relTol,
LAMBDA && assembleFunction )
{
- CompositionalMultiphaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() );
localIndex const NC = flowSolver.numFluidComponents();
@@ -510,7 +515,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio
wellElemCompDens.move( hostMemorySpace, false );
arrayView1d< real64 > const & connRate =
- subRegion.getField< fields::well::mixtureConnectionRate >();
+ subRegion.getField< fields::well::connectionRate >();
connRate.move( hostMemorySpace, false );
// a) compute all the derivatives wrt to the pressure in WELL elem iwelem
@@ -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,23 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( time, dt, domain );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.initializeWell( domain, meshLevel, subRegion, time );
+ } );
+ } );
}
static real64 constexpr time = 0.0;
@@ -699,7 +720,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellAccumulationTerms( time, dt, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
#endif
diff --git a/src/coreComponents/integrationTests/wellsTests/testOpenClosePerf.cpp b/src/coreComponents/integrationTests/wellsTests/testOpenClosePerf.cpp
index c45c9a21e68..d0826f8b9f4 100644
--- a/src/coreComponents/integrationTests/wellsTests/testOpenClosePerf.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testOpenClosePerf.cpp
@@ -57,18 +57,24 @@ char const * PreXmlInput =
temperature="297.15"
useMass="0">
-
-
-
+
+
+
+
+
& solv
LAMBDA && perfFunction )
{
- CompositionalMultiphaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
typedef stdMap< real64, std::vector< int > > map_type;
map_type refVal;
@@ -217,7 +223,7 @@ void testPlugBottomUpPerfCheck( CompositionalMultiphaseReservoirAndWells<> & sol
LAMBDA && perfFunction )
{
- CompositionalMultiphaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
typedef stdMap< real64, std::vector< int > > map_type;
map_type refVal;
@@ -260,7 +266,7 @@ void testOpenTopDownPerfCheck( CompositionalMultiphaseReservoirAndWells<> & solv
LAMBDA && perfFunction )
{
- CompositionalMultiphaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
typedef stdMap< real64, std::vector< int > > map_type;
map_type refPerfTable;
@@ -302,7 +308,7 @@ void testOpenBottomUpPerfCheck( CompositionalMultiphaseReservoirAndWells<> & sol
LAMBDA && perfFunction )
{
- CompositionalMultiphaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
typedef stdMap< real64, std::vector< int > > map_type;
map_type refVal;
@@ -516,8 +522,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, plugTopDownPerfCheck )
testPlugTopDownPerfCheck( *solver, domain,
[&] ( real64 time )
{
- WellSolverBase * wellSolverBase = solver->wellSolver();
- wellSolverBase->setPerforationStatus( time, domain );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.setPerforationStatus( time, subRegion );
+ } );
+ } );
} );
}
@@ -530,8 +551,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, plugBottomUpPerfCheck )
testPlugBottomUpPerfCheck( *solver, domain,
[&] ( real64 time )
{
- WellSolverBase * wellSolverBase = solver->wellSolver();
- wellSolverBase->setPerforationStatus( time, domain );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.setPerforationStatus( time, subRegion );
+ } );
+ } );
} );
}
TEST_F( CompositionalMultiphaseReservoirSolverTest, openTopDownPerfCheck )
@@ -543,8 +579,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, openTopDownPerfCheck )
testOpenTopDownPerfCheck( *solver, domain,
[&] ( real64 time )
{
- WellSolverBase * wellSolverBase = solver->wellSolver();
- wellSolverBase->setPerforationStatus( time, domain );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.setPerforationStatus( time, subRegion );
+ } );
+ } );
} );
}
@@ -557,8 +608,24 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, openBottomUpPerfCheck )
testOpenBottomUpPerfCheck( *solver, domain,
[&] ( real64 time )
{
- WellSolverBase * wellSolverBase = solver->wellSolver();
- wellSolverBase->setPerforationStatus( time, domain );
+
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.setPerforationStatus( time, subRegion );
+ } );
+ } );
} );
}
diff --git a/src/coreComponents/integrationTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp
index f1ca32e9e81..3b5639a588c 100644
--- a/src/coreComponents/integrationTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp
@@ -57,26 +57,38 @@ char const * xmlInput =
temperature="297.15"
useMass="0">
-
-
-
+
+
+
+
+
+
+
+
& solver,
real64 const relTol,
LAMBDA && assembleFunction )
{
- CompositionalMultiphaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() );
localIndex const NC = flowSolver.numFluidComponents();
@@ -366,7 +378,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells<> & solver,
wellElemCompDens.move( hostMemorySpace, false );
arrayView1d< real64 > const & connRate =
- subRegion.getField< fields::well::mixtureConnectionRate >();
+ subRegion.getField< fields::well::connectionRate >();
connRate.move( hostMemorySpace, false );
// a) compute all the derivatives wrt to the pressure in WELL elem iwelem
@@ -483,6 +495,23 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( time, dt, domain );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.initializeWell( domain, meshLevel, subRegion, time );
+ } );
+ } );
}
static real64 constexpr time = 0.0;
@@ -528,7 +557,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleFluxTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellFluxTerms( time, dt, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
@@ -545,7 +590,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Press
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellPressureRelations( time, dt, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
diff --git a/src/coreComponents/integrationTests/wellsTests/testReservoirSinglePhaseMSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testReservoirSinglePhaseMSWells.cpp
index d75ad50a957..5b15ed993e3 100644
--- a/src/coreComponents/integrationTests/wellsTests/testReservoirSinglePhaseMSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testReservoirSinglePhaseMSWells.cpp
@@ -58,22 +58,35 @@ char const * PreXmlInput =
discretization="singlePhaseTPFA"
targetRegions="{Region1}">
-
-
-
-
+
+
+
+
+
+
+
+
+
+
& solver,
real64 const relTol,
LAMBDA && assembleFunction )
{
- SinglePhaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
SinglePhaseFVM< SinglePhaseBase > & flowSolver = dynamicCast< SinglePhaseFVM< SinglePhaseBase > & >( *solver.reservoirSolver() );
CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix();
@@ -357,6 +370,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( TIME, DT, domain );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.initializeWell( domain, meshLevel, subRegion, TIME );
+ } );
+ } );
}
void TestAssembleCouplingTerms()
@@ -385,7 +415,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleFluxTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellFluxTerms( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
@@ -400,7 +446,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assemblePressureRelations( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellPressureRelations( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
@@ -415,7 +477,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleAccumulationTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellAccumulationTerms( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
@@ -497,7 +575,24 @@ TEST_F( SinglePhaseReservoirSolverInternalWellTest, jacobianNumericalCheck_Flux
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleFluxTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellFluxTerms( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
diff --git a/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells.cpp
index d10f1da56f6..4a8c5a28a67 100644
--- a/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells.cpp
@@ -60,27 +60,40 @@ char const * PreXmlInput =
discretization="singlePhaseTPFA"
targetRegions="{Region1}">
-
-
-
-
+
+
+
+
+
+
+
+
+
+
& solver,
LAMBDA && assembleFunction )
{
GEOS_UNUSED_VAR( testName );
- SinglePhaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
SinglePhaseFVM< SinglePhaseBase > & flowSolver = dynamicCast< SinglePhaseFVM< SinglePhaseBase > & >( *solver.reservoirSolver() );
CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix();
@@ -515,6 +528,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( TIME, DT, domain );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.initializeWell( domain, meshLevel, subRegion, TIME );
+ } );
+ } );
}
void TestAssembleCouplingTerms()
@@ -543,7 +573,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleFluxTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellFluxTerms( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
@@ -557,7 +603,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assemblePressureRelations( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellPressureRelations( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
@@ -572,7 +634,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleAccumulationTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellAccumulationTerms( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
@@ -654,7 +732,24 @@ TEST_F( SinglePhaseReservoirSolverInternalWellTest, jacobianNumericalCheck_Flux
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleFluxTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellFluxTerms( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
diff --git a/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells_RateInj.cpp b/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells_RateInj.cpp
index 255b0201692..5f69fb1b97c 100644
--- a/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells_RateInj.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells_RateInj.cpp
@@ -73,26 +73,30 @@ char const * XmlInput =
targetRegions="{ region }">
-
-
+
+ referenceElevation="-0.01"/>
+
+
@@ -305,7 +309,7 @@ void testNumericalJacobian( SinglePhaseReservoirAndWells<> & solver,
{
GEOS_UNUSED_VAR( testName );
- SinglePhaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
SinglePhaseFVM< SinglePhaseBase > & flowSolver = dynamicCast< SinglePhaseFVM< SinglePhaseBase > & >( *solver.reservoirSolver() );
CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix();
@@ -597,6 +601,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( TIME, DT, domain );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.initializeWell( domain, meshLevel, subRegion, TIME );
+ } );
+ } );
}
void TestAssembleCouplingTerms()
@@ -624,7 +645,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleFluxTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellFluxTerms( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
@@ -638,7 +675,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assemblePressureRelations( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellPressureRelations( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
@@ -653,7 +706,23 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleAccumulationTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellAccumulationTerms( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
@@ -710,7 +779,24 @@ TEST_F( SinglePhaseReservoirSolverInternalWellTest, jacobianNumericalCheck_Flux
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleFluxTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs );
+
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellFluxTerms( TIME, DT, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
diff --git a/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp
index 98aa57a5c84..4ae6c8f47a6 100644
--- a/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp
@@ -96,28 +96,33 @@ char const * xmlInput =
targetRegions="{ region }">
-
-
-
+ surfaceTemperature="300.15">
+
+
+
+
@@ -328,7 +333,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio
real64 const relTol, bool diag_check,
LAMBDA && assembleFunction )
{
- CompositionalMultiphaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() );
localIndex const NC = flowSolver.numFluidComponents();
@@ -537,7 +542,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio
wellElemCompDens.move( hostMemorySpace, false );
arrayView1d< real64 > const & connRate =
- subRegion.getField< fields::well::mixtureConnectionRate >();
+ subRegion.getField< fields::well::connectionRate >();
connRate.move( hostMemorySpace, false );
// a) compute all the derivatives wrt to the pressure in WELL elem iwelem
@@ -699,6 +704,24 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( time, dt, domain );
+
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.initializeWell( domain, meshLevel, subRegion, time );
+ } );
+ } );
}
static real64 constexpr time = 0.0;
@@ -784,7 +807,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellAccumulationTerms( time, dt, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel )
@@ -798,7 +837,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Press
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellPressureRelations( time, dt, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
#endif
diff --git a/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp
index 76fa20d4cea..722be4fb77a 100644
--- a/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp
@@ -97,28 +97,33 @@ char const * xmlInput =
targetRegions="{ region }">
-
-
-
+ surfaceTemperature="300.15">
+
+
+
+
@@ -329,7 +334,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio
real64 const relTol, bool diag_check,
LAMBDA && assembleFunction )
{
- CompositionalMultiphaseWell & wellSolver = *solver.wellSolver();
+ WellManager & wellSolver = *solver.wellSolver();
CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() );
localIndex const NC = flowSolver.numFluidComponents();
@@ -539,7 +544,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio
wellElemCompDens.move( hostMemorySpace, false );
arrayView1d< real64 > const & connRate =
- subRegion.getField< fields::well::mixtureConnectionRate >();
+ subRegion.getField< fields::well::connectionRate >();
connRate.move( hostMemorySpace, false );
// a) compute all the derivatives wrt to the pressure in WELL elem iwelem
@@ -688,6 +693,23 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( time, dt, domain );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.initializeWell( domain, meshLevel, subRegion, time );
+ } );
+ } );
}
static real64 constexpr time = 0.0;
@@ -773,7 +795,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellAccumulationTerms( time, dt, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel )
@@ -787,7 +825,23 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Press
[&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs );
+ WellManager & wellSolver = *solver->wellSolver();
+ wellSolver.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 = wellSolver.getWellControls( subRegion );
+ wellControls.assembleWellPressureRelations( time, dt, subRegion, solver->getDofManager(), localMatrix, localRhs );
+ } );
+ } );
} );
}
#endif
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 6eb55e9775a..bebc6d1aa58 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
+++ b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
@@ -129,11 +129,22 @@ set( fluidFlowSolvers_headers
wells/SinglePhaseWellFields.hpp
wells/WellConstants.hpp
wells/WellControls.hpp
- wells/WellSolverBase.hpp
- wells/WellSolverBaseFields.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/WellManager.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 )
@@ -165,7 +176,15 @@ set( fluidFlowSolvers_sources
wells/SinglePhaseWell.cpp
wells/kernels/SinglePhaseWellKernels.cpp
wells/WellControls.cpp
- wells/WellSolverBase.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/WellManager.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 9f18e9741da..03b1f9772f1 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
@@ -64,15 +74,14 @@ using namespace fields;
CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name,
Group * const parent )
:
- WellSolverBase( name, parent ),
+ WellControls( name, parent ),
m_useMass( false ),
m_useTotalMassEquation( 1 ),
m_maxCompFracChange( 1.0 ),
m_maxRelativePresChange( 0.2 ),
m_maxAbsolutePresChange( -1 ), // disabled by default
m_minScalingFactor( 0.01 ),
- m_allowCompDensChopping( 1 ),
- m_targetPhaseIndex( -1 )
+ m_allowCompDensChopping( 1 )
{
this->registerWrapper( viewKeyStruct::useMassFlagString(), &m_useMass ).
setApplyDefaultValue( 0 ).
@@ -123,7 +132,7 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name,
void CompositionalMultiphaseWell::postInputInitialization()
{
- WellSolverBase::postInputInitialization();
+ WellControls::postInputInitialization();
GEOS_ERROR_IF_GT_MSG( m_maxCompFracChange, 1.0,
"The maximum absolute change in component fraction must smaller or equal to 1.0",
@@ -135,29 +144,24 @@ void CompositionalMultiphaseWell::postInputInitialization()
GEOS_ERROR_IF_LE_MSG( m_maxRelativeCompDensChange, 0.0,
"The maximum relative change in component density must be larger than 0.0",
getWrapperDataContext( viewKeyStruct::maxRelativeCompDensChangeString() ) );
+
+}
+void CompositionalMultiphaseWell::setConstitutiveNames( ElementSubRegionBase & subRegion ) const
+{
+ setConstitutiveName< MultiFluidBase >( subRegion, viewKeyStruct::fluidNamesString(), "multiphase fluid" );
}
-void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies )
+void CompositionalMultiphaseWell::registerWellDataOnMesh( WellElementSubRegion & subRegion )
{
- WellSolverBase::registerDataOnMesh( meshBodies );
+ WellControls::registerWellDataOnMesh( subRegion );
+ setConstitutiveNames ( subRegion );
DomainPartition const & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" );
ConstitutiveManager const & cm = domain.getConstitutiveManager();
-
- forDiscretizationOnMeshTargets( meshBodies, [&]( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+ if( m_referenceFluidModelName.empty() )
{
- mesh.getElemManager().forElementSubRegions( regionNames,
- [&]( localIndex const,
- ElementSubRegionBase & subRegion )
- {
- if( m_referenceFluidModelName.empty() )
- {
- m_referenceFluidModelName = getConstitutiveName< MultiFluidBase >( subRegion );
- }
- } );
- } );
+ m_referenceFluidModelName = getConstitutiveName< MultiFluidBase >( subRegion );
+ }
// 1. Set key dimensions of the problem
// Empty check needed to avoid errors when running in schema generation mode.
@@ -172,131 +176,116 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies )
// 1 pressure + NC compositions + temp if thermal
m_numDofPerResElement = isThermal() ? m_numComponents + 2 : m_numComponents + 1;
- // loop over the wells
- forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+
+ string const & fluidName = getConstitutiveName< MultiFluidBase >( subRegion );
+ MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
+
+ // The resizing of the arrays needs to happen here, before the call to initializePreSubGroups,
+ // to make sure that the dimensions are properly set before the timeHistoryOutput starts its initialization.
+ subRegion.registerField< well::pressure >( getName() );
+ subRegion.registerField< well::pressure_n >( getName() );
+
+ subRegion.registerField< well::temperature >( getName() );
+ if( isThermal() )
{
+ subRegion.registerField< well::temperature_n >( getName() );
+ }
- ElementRegionManager & elemManager = mesh.getElemManager();
+ subRegion.registerField< well::gravityCoefficient >( getName() );
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
- {
- string const & fluidName = getConstitutiveName< MultiFluidBase >( subRegion );
- MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
-
- // The resizing of the arrays needs to happen here, before the call to initializePreSubGroups,
- // to make sure that the dimensions are properly set before the timeHistoryOutput starts its initialization.
-
- subRegion.registerField< well::globalCompDensity >( getName() ).
- reference().resizeDimension< 1 >( m_numComponents );
- subRegion.registerField< well::globalCompDensity_n >( getName() ).
- reference().resizeDimension< 1 >( m_numComponents );
-
- subRegion.registerField< well::mixtureConnectionRate >( getName() );
- subRegion.registerField< well::mixtureConnectionRate_n >( getName() );
-
- subRegion.registerField< well::globalCompFraction >( getName() ).
- setDimLabels( 1, fluid.componentNames() ).
- reference().resizeDimension< 1 >( m_numComponents );
- subRegion.registerField< well::dGlobalCompFraction_dGlobalCompDensity >( getName() ).
- reference().resizeDimension< 1, 2 >( m_numComponents, m_numComponents );
-
- subRegion.registerField< well::phaseVolumeFraction >( getName() ).
- setDimLabels( 1, fluid.phaseNames() ).
- reference().resizeDimension< 1 >( m_numPhases );
- subRegion.registerField< well::dPhaseVolumeFraction >( getName() ).
- reference().resizeDimension< 1, 2 >( m_numPhases, m_numComponents + 2 ); // dP, dT, dC
-
- subRegion.registerField< well::totalMassDensity >( getName() );
- subRegion.registerField< well::dTotalMassDensity >( getName() ).
- reference().resizeDimension< 1 >( m_numComponents +2 ); // dP, dT, dC
-
- subRegion.registerField< well::phaseVolumeFraction_n >( getName() ).
- reference().resizeDimension< 1 >( m_numPhases );
-
- subRegion.registerField< well::pressureScalingFactor >( getName() );
- subRegion.registerField< well::temperatureScalingFactor >( getName() );
- subRegion.registerField< well::globalCompDensityScalingFactor >( getName() );
-
- PerforationData & perforationData = *subRegion.getPerforationData();
- perforationData.registerField< well::compPerforationRate >( getName() ).
- reference().resizeDimension< 1 >( m_numComponents );
-
- perforationData.registerField< well::dCompPerforationRate >( getName() ).
- reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 );
- if( fluid.isThermal() )
- {
- perforationData.registerField< well::energyPerforationFlux >( getName() );
- perforationData.registerField< well::dEnergyPerforationFlux >( getName() ).
- reference().resizeDimension< 1, 2 >( 2, m_numComponents+2 );
- }
- WellControls & wellControls = getWellControls( subRegion );
- wellControls.registerWrapper< real64 >( viewKeyStruct::currentBHPString() );
+ subRegion.registerField< well::globalCompDensity >( getName() ).
+ reference().resizeDimension< 1 >( m_numComponents );
+ subRegion.registerField< well::globalCompDensity_n >( getName() ).
+ reference().resizeDimension< 1 >( m_numComponents );
- wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ).
- setSizedFromParent( 0 ).
- reference().resizeDimension< 0 >( m_numComponents + 2 ); // dP, dT, dC
+ subRegion.registerField< well::connectionRate >( getName() );
+ subRegion.registerField< well::connectionRate_n >( getName() );
- wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::currentPhaseVolRateString() ).
- setSizedFromParent( 0 ).
- reference().resizeDimension< 0 >( m_numPhases );
+ subRegion.registerField< well::globalCompFraction >( getName() ).
+ setDimLabels( 1, fluid.componentNames() ).
+ reference().resizeDimension< 1 >( m_numComponents );
+ subRegion.registerField< well::dGlobalCompFraction_dGlobalCompDensity >( getName() ).
+ reference().resizeDimension< 1, 2 >( m_numComponents, m_numComponents );
- wellControls.registerWrapper< array2d< real64 > >( viewKeyStruct::dCurrentPhaseVolRateString() ).
- setSizedFromParent( 0 ).
- reference().resizeDimension< 0, 1 >( m_numPhases, m_numComponents + 3 ); // dP, dT, dC, dQ
+ subRegion.registerField< well::phaseVolumeFraction >( getName() ).
+ setDimLabels( 1, fluid.phaseNames() ).
+ reference().resizeDimension< 1 >( m_numPhases );
+ subRegion.registerField< well::dPhaseVolumeFraction >( getName() ).
+ reference().resizeDimension< 1, 2 >( m_numPhases, m_numComponents + 2 ); // dP, dT, dC
- wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() );
+ subRegion.registerField< well::totalMassDensity >( getName() );
+ subRegion.registerField< well::dTotalMassDensity >( getName() ).
+ reference().resizeDimension< 1 >( m_numComponents +2 ); // dP, dT, dC
- wellControls.registerWrapper< real64 >( viewKeyStruct::currentTotalVolRateString() );
- wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentTotalVolRateString() ).
- setSizedFromParent( 0 ).
- reference().resizeDimension< 0 >( m_numComponents + 3 ); // dP, dT, dC dQ
+ subRegion.registerField< well::phaseVolumeFraction_n >( getName() ).
+ reference().resizeDimension< 1 >( m_numPhases );
- wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() );
+ subRegion.registerField< well::pressureScalingFactor >( getName() );
+ subRegion.registerField< well::temperatureScalingFactor >( getName() );
+ subRegion.registerField< well::globalCompDensityScalingFactor >( getName() );
- wellControls.registerWrapper< real64 >( viewKeyStruct::currentMassRateString() );
+ PerforationData & perforationData = *subRegion.getPerforationData();
- // write rates output header
- // the rank that owns the reference well element is responsible
- if( m_writeCSV > 0 && subRegion.isLocallyOwned() )
- {
- string const fileName = GEOS_FMT( "{}/{}.csv", m_ratesOutputDir, wellControls.getName() );
- string const massUnit = m_useMass ? "kg" : "mol";
- integer const useSurfaceConditions = wellControls.useSurfaceConditions();
- string const conditionKey = useSurfaceConditions ? "surface" : "reservoir";
- string const unitKey = useSurfaceConditions ? "s" : "r";
- integer const numPhase = m_numPhases;
- integer const numComp = m_numComponents;
- // format: time,bhp,total_rate,total_vol_rate,phase0_vol_rate,phase1_vol_rate,...
- makeDirsForPath( m_ratesOutputDir );
- GEOS_LOG( GEOS_FMT( "{}: Rates CSV generated at {}", getName(), fileName ) );
- std::ofstream outputFile( fileName );
- outputFile << "Time [s],dt[s],BHP [Pa],Total rate [" << massUnit << "/s],Total " << conditionKey << " volumetric rate [" << unitKey << "m3/s]";
- for( integer ip = 0; ip < numPhase; ++ip )
- {
- outputFile << ",Phase" << ip << " " << conditionKey << " volumetric rate [" << unitKey << "m3/s]";
- }
- for( integer ic = 0; ic < numComp; ++ic )
- {
- outputFile << ",Component" << ic << " rate [" << massUnit << "/s]";
- }
- outputFile << std::endl;
- outputFile.close();
- }
- } );
- } );
+ perforationData.registerField< well::gravityCoefficient >( getName() );
+ perforationData.registerField< well::compPerforationRate >( getName() ).
+ reference().resizeDimension< 1 >( m_numComponents );
+
+ perforationData.registerField< well::dCompPerforationRate >( getName() ).
+ reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 );
+ if( fluid.isThermal() )
+ {
+ perforationData.registerField< well::energyPerforationFlux >( getName() );
+ perforationData.registerField< well::dEnergyPerforationFlux >( getName() ).
+ reference().resizeDimension< 1, 2 >( 2, m_numComponents+2 );
+ }
+
+ registerWrapper< real64 >( viewKeyStruct::currentBHPString() );
+
+ registerWrapper< array1d< real64 > >( viewKeyStruct::currentPhaseVolRateString() ).
+ setSizedFromParent( 0 ).
+ reference().resizeDimension< 0 >( m_numPhases );
+
+ registerWrapper< real64 >( viewKeyStruct::massDensityString() );
+
+ registerWrapper< real64 >( viewKeyStruct::currentTotalVolRateString() );
+
+ registerWrapper< real64 >( viewKeyStruct::massDensityString() );
+
+ registerWrapper< real64 >( viewKeyStruct::currentMassRateString() );
+
+ // write rates output header
+ // the rank that owns the reference well element is responsible
+ if( m_writeCSV > 0 && subRegion.isLocallyOwned() )
+ {
+ string const fileName = GEOS_FMT( "{}/{}.csv", m_ratesOutputDir, getName() );
+ string const massUnit = m_useMass ? "kg" : "mol";
+ integer const useSurfaceConditions = this->useSurfaceConditions();
+ string const conditionKey = useSurfaceConditions ? "surface" : "reservoir";
+ string const unitKey = useSurfaceConditions ? "s" : "r";
+ integer const numPhase = m_numPhases;
+ integer const numComp = m_numComponents;
+ // format: time,bhp,total_rate,total_vol_rate,phase0_vol_rate,phase1_vol_rate,...
+ makeDirsForPath( m_ratesOutputDir );
+ GEOS_LOG( GEOS_FMT( "{}: Rates CSV generated at {}", getName(), fileName ) );
+ std::ofstream outputFile( fileName );
+ outputFile << "Time [s],dt[s],BHP [Pa],Total rate [" << massUnit << "/s],Total " << conditionKey << " volumetric rate [" << unitKey << "m3/s]";
+ for( integer ip = 0; ip < numPhase; ++ip )
+ {
+ outputFile << ",Phase" << ip << " " << conditionKey << " volumetric rate [" << unitKey << "m3/s]";
+ }
+ for( integer ic = 0; ic < numComp; ++ic )
+ {
+ outputFile << ",Component" << ic << " rate [" << massUnit << "/s]";
+ }
+ outputFile << std::endl;
+ outputFile.close();
+ }
-}
-void CompositionalMultiphaseWell::setConstitutiveNames( ElementSubRegionBase & subRegion ) const
-{
- setConstitutiveName< MultiFluidBase >( subRegion, viewKeyStruct::fluidNamesString(), "multiphase fluid" );
}
+
namespace
{
@@ -340,15 +329,18 @@ void compareMulticomponentModels( MODEL1_TYPE const & lhs, MODEL2_TYPE const & r
* @brief Checks if the WellControls parameters are within the fluid tables ranges
* @param fluid the fluid to check
*/
-void CompositionalMultiphaseWell::validateWellControlsForFluid( WellControls const & wellControls,
- MultiFluidBase const & fluid ) const
+void CompositionalMultiphaseWell::validateFluidModel(
+ constitutive::MultiFluidBase const & fluid, constitutive::MultiFluidBase const & referenceFluid ) const
{
- if( wellControls.useSurfaceConditions() )
+
+ compareMultiphaseModels( fluid, referenceFluid );
+ compareMulticomponentModels( fluid, referenceFluid );
+ if( useSurfaceConditions() )
{
try
{
- real64 const & surfaceTemp = wellControls.getSurfaceTemperature();
- real64 const & surfacePres = wellControls.getSurfacePressure();
+ real64 const & surfaceTemp = getSurfaceTemperature();
+ real64 const & surfacePres = getSurfacePressure();
fluid.checkTablesParameters( surfacePres, surfaceTemp );
} catch( SimulationError const & ex )
{
@@ -361,95 +353,33 @@ void CompositionalMultiphaseWell::validateWellControlsForFluid( WellControls con
}
}
-void CompositionalMultiphaseWell::validateConstitutiveModels( DomainPartition const & domain ) const
-{
- GEOS_MARK_FUNCTION;
-
- ConstitutiveManager const & cm = domain.getConstitutiveManager();
- CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
- string const referenceFluidName = flowSolver.referenceFluidModelName();
- MultiFluidBase const & referenceFluid = cm.getConstitutiveRelation< MultiFluidBase >( m_referenceFluidModelName );
-
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
- MeshLevel const & mesh,
- string_array const & regionNames )
- {
-
- mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
- WellElementSubRegion const & subRegion )
- {
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
- compareMultiphaseModels( fluid, referenceFluid );
- compareMulticomponentModels( fluid, referenceFluid );
-
- WellControls const & wellControls = getWellControls( subRegion );
- validateWellControlsForFluid( wellControls, fluid );
- } );
-
- } );
-}
-
-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 ),
- "Injection stream not specified for well ",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( ( streamSize != m_numComponents ),
- "Injection stream for well should have " << m_numComponents << " components.",
- InputError, wellControls.getDataContext() );
-
- 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 ),
- "Invalid injection stream for well ",
- InputError, wellControls.getDataContext() );
- compFracSum += compFrac;
- }
- GEOS_THROW_IF( ( compFracSum < 1.0 - std::numeric_limits< real64 >::epsilon() ) ||
- ( compFracSum > 1.0 + std::numeric_limits< real64 >::epsilon() ),
- "Invalid injection stream for well ",
- InputError, wellControls.getDataContext() );
- }
-}
-
void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n,
real64 const & GEOS_UNUSED_PARAM( dt ),
WellElementSubRegion const & subRegion )
{
- WellControls & wellControls = getWellControls( subRegion );
- if( !wellControls.useSurfaceConditions() )
+ GEOS_UNUSED_VAR( time_n );
+
+ if( !useSurfaceConditions() )
{
- bool const useSeg =wellControls.referenceReservoirRegion().empty();
+ bool const useSeg = getReferenceReservoirRegion().empty();
GEOS_WARNING_IF( useSeg,
"WellControls " <( getFlowSolverName() );
+ string const regionName = getReferenceReservoirRegion();
+ CompositionalMultiphaseBase const & flowSolver = getParent().getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
string_array const & targetRegionsNames = flowSolver.getTargetRegionNames();
auto const pos = std::find( targetRegionsNames.begin(), targetRegionsNames.end(), regionName );
GEOS_ERROR_IF( pos == targetRegionsNames.end(),
- GEOS_FMT( "Region {} is not a target of the reservoir solver and cannot be used for referenceReservoirRegion in WellControl {}.",
- regionName, wellControls.getName() ),
- getDataContext() );
+ GEOS_FMT( "{}: Region {} is not a target of the reservoir solver and cannot be used for referenceReservoirRegion in WellControl {}.",
+ getDataContext(), regionName, getName() ) );
}
@@ -457,125 +387,66 @@ 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,
- "Phase rate control is not available for injectors",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( wellControls.isProducer() && currentControl == WellControls::Control::TOTALVOLRATE,
- "Total rate control is not available for producers",
- InputError, wellControls.getDataContext() );
-
- GEOS_THROW_IF( wellControls.isInjector() && targetTotalRate < 0.0,
- "Target total rate cannot be negative for injectors",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( wellControls.isInjector() && !isZero( targetPhaseRate ),
- "Target phase rate cannot be used for injectors",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( wellControls.isProducer() && !isZero( targetTotalRate ),
- "Target total rate cannot be used for producers",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( wellControls.isProducer() && !isZero( targetMassRate ),
- "Target mass rate cannot be used for producers",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( !m_useMass && !isZero( targetMassRate ),
- "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,
- "Target phase rate cannot be negative for producers",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( wellControls.isProducer() && !isZero( targetTotalRate ),
- "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,
- "Phase " << wellControls.getTargetPhaseName() << " not found",
- InputError, wellControls.getDataContext() );
+ // tjb
+ forSubGroups< InjectionConstraint< PhaseVolumeRateConstraint >, ProductionConstraint< PhaseVolumeRateConstraint > >( [&]( auto & constraint )
+ {
+ constraint.validatePhaseType( fluid );
+ } );
+
+
+
}
void CompositionalMultiphaseWell::initializePostSubGroups()
{
- WellSolverBase::initializePostSubGroups();
+ WellControls::initializePostSubGroups();
- DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" );
+ //DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" );
- validateConstitutiveModels( domain );
+ // tjbvalidateConstitutiveModels( 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()
{
- WellSolverBase::initializePostInitialConditionsPreSubGroups();
- createSeparator();
+ WellControls::initializePostInitialConditionsPreSubGroups();
+
}
-void CompositionalMultiphaseWell::postRestartInitialization()
+void CompositionalMultiphaseWell::initializeWellPostInitialConditionsPreSubGroups( WellElementSubRegion & subRegion )
{
- 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 )
- {
- // setup fluid separator
- WellControls & wellControls = getWellControls( subRegion );
- constitutive::MultiFluidBase & fluidSeparator = wellControls.getMultiFluidSeparator();
- fluidSeparator.allocateConstitutiveData( wellControls, 1 );
- fluidSeparator.resize( 1 );
- } );
- } );
+ // set gravity coefficient
+ setGravCoef( subRegion, getParent().getParent().getReference< R1Tensor >( PhysicsSolverManager::viewKeyStruct::gravityVectorString() ));
+
+ // setup fluid model
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ constitutive::MultiFluidBase & fluid = subRegion.getConstitutiveModel< constitutive::MultiFluidBase >( fluidName );
+ fluid.setMassFlag( m_useMass );
+ createSeparator( subRegion );
+}
+void CompositionalMultiphaseWell::postRestartInitialization( )
+{
+
+ // setup fluid separator
+ constitutive::MultiFluidBase & fluidSeparator = getMultiFluidSeparator();
+ fluidSeparator.allocateConstitutiveData( *this, 1 );
+ fluidSeparator.resize( 1 );
+
}
-void CompositionalMultiphaseWell::createSeparator()
+void CompositionalMultiphaseWell::createSeparator( WellElementSubRegion & subRegion )
{
- 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() );
- MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
- fluid.setMassFlag( m_useMass );
- // 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 ));
- } );
- } );
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
+ fluid.setMassFlag( m_useMass );
+ // setup fluid separator
+ string const fluidSeparatorName = getName() + "Separator";
+ std::unique_ptr< constitutive::ConstitutiveBase > fluidSeparatorPtr = fluid.deliverClone( fluidSeparatorName, this );
+ fluidSeparatorPtr->allocateConstitutiveData( *this, 1 );
+ fluidSeparatorPtr->resize( 1 );
+ setFluidSeparator( std::move( fluidSeparatorPtr ));
+
}
void CompositionalMultiphaseWell::updateGlobalComponentFraction( WellElementSubRegion & subRegion ) const
{
@@ -597,70 +468,41 @@ 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();
+ string const wellControlsName = getName();
+ real64 const & refGravCoef = 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 )
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() );
+ // 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 ) );
}
-void CompositionalMultiphaseWell::updateVolRatesForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion const & subRegion )
+void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubRegion const & subRegion )
{
GEOS_MARK_FUNCTION;
@@ -670,252 +512,201 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( ElementRegionMana
return;
}
- integer constexpr maxNumComp = constitutive::MultiFluidBase::MAX_NUM_COMPONENTS;
- integer const numComp = m_numComponents;
+
integer const numPhase = m_numPhases;
localIndex const iwelemRef = subRegion.getTopWellElementIndex();
- WellControls & wellControls = getWellControls( subRegion );
-
// 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 >();
+ arrayView1d< real64 const > const & connRate = subRegion.getField< well::connectionRate >();
// 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();
+ constitutive::MultiFluidBase & fluidSeparator = 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_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";
+ string const wellControlsName = getName();
- 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 =
+ getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
+
+ real64 & currentTotalVolRate =
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
+
+ real64 & currentMassRate =
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() );
+
+ real64 & massDensity =
+ 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( !wellControls.referenceReservoirRegion().empty() )
- {
- ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion());
- GEOS_ERROR_IF ( !region.hasWrapper( CompositionalMultiphaseStatistics::regionStatisticsName() ),
- GEOS_FMT( "WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ",
- wellControls.getName(), wellControls.referenceReservoirRegion() ),
- getDataContext() );
+ // Step 1: update the total volume rate
- CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< CompositionalMultiphaseStatistics::RegionStatistics >(
- CompositionalMultiphaseStatistics::regionStatisticsName() );
- wellControls.setRegionAveragePressure( stats.averagePressure );
- wellControls.setRegionAverageTemperature( stats.averageTemperature );
- GEOS_ERROR_IF( stats.averagePressure <= 0.0,
- GEOS_FMT( "No region average quantities computed. WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ",
- wellControls.getName(), wellControls.referenceReservoirRegion() ),
- getDataContext());
- }
- // 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
+ 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();
+
+
+
+ // subRegion data
+ arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::connectionRate >();
+
+ // fluid data
+ constitutive::MultiFluidBase & fluidSeparator = 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 = getName();
+ bool const logSurfaceCondition = isLogLevelActive< logInfo::BoundaryConditions >( getLogLevel());
+ string const massUnit = m_useMass ? "kg" : "mol";
+
+ integer const useSurfCond = useSurfaceConditions();
+
arrayView1d< real64 > const & currentPhaseVolRate =
- wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
- arrayView2d< real64 > const & dCurrentPhaseVolRate =
- wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() );
+ getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
real64 & currentTotalVolRate =
- wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
real64 & currentMassRate =
- wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() );
-
- arrayView1d< real64 > const & dCurrentTotalVolRate =
- wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() );
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() );
real64 & massDensity =
- wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() );
+ 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,
+ &useSurfCond,
+ ¤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 && useSurfCond )
+ {
+ 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 && useSurfCond )
+ {
+ 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;
@@ -942,19 +733,129 @@ void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRe
}
-real64 CompositionalMultiphaseWell::updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const
+void CompositionalMultiphaseWell::updateSeparator( ElementRegionManager const & elemManager, 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,
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+
+ // 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 >();
+
+
+ // fluid data
+ constitutive::MultiFluidBase & fluidSeparator = getMultiFluidSeparator();
+
+ // control data
+
+ string const wellControlsName = getName();
+ bool const logSurfaceCondition = isLogLevelActive< logInfo::BoundaryConditions >( getLogLevel());
+ string const massUnit = m_useMass ? "kg" : "mol";
+
+ integer const useSurfaceCond = useSurfaceConditions();
+ real64 flashPressure;
+ real64 flashTemperature;
+ if( useSurfaceCond )
+ {
+ // use surface conditions
+ flashPressure = getSurfacePressure();
+ flashTemperature = getSurfaceTemperature();
+ }
+ else
+ {
+ if( !getReferenceReservoirRegion().empty() )
+ {
+ ElementRegionBase const & region = elemManager.getRegion( getReferenceReservoirRegion() );
+ GEOS_ERROR_IF ( !region.hasWrapper( CompositionalMultiphaseStatistics::regionStatisticsName()),
+ GEOS_FMT( "{}: WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ",
+ getDataContext(), getName(), getReferenceReservoirRegion() ) );
+
+ CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< CompositionalMultiphaseStatistics::RegionStatistics >(
+ CompositionalMultiphaseStatistics::regionStatisticsName() );
+ GEOS_ERROR_IF( stats.averagePressure <= 0.0,
+ GEOS_FMT(
+ "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ",
+ getDataContext(), getName(), getReferenceReservoirRegion() ));
+ setRegionAveragePressure( stats.averagePressure );
+ setRegionAverageTemperature( stats.averageTemperature );
+ }
+ // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions
+ flashPressure = getRegionAveragePressure();
+ if( flashPressure < 0.0 )
+ {
+ // region name not set, use segment conditions
+ flashPressure = pres[iwelemRef];
+ flashTemperature = temp[iwelemRef];
+ }
+ else
+ {
+ // use reservoir region averages
+ flashTemperature = 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,
+ useSurfaceCond,
+ 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( useSurfaceCond )
+ {
+ // 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::
@@ -990,185 +891,273 @@ void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion &
}
-void CompositionalMultiphaseWell::updateState( DomainPartition & domain )
+real64 CompositionalMultiphaseWell::updateWellState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion )
{
GEOS_MARK_FUNCTION;
- real64 maxPhaseVolFrac = 0.0;
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
- {
- ElementRegionManager & elemManager = mesh.getElemManager();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
- WellElementSubRegion & subRegion )
- {
- WellControls & wellControls = getWellControls( subRegion );
- if( wellControls.getWellStatus() == WellControls::Status::OPEN )
- {
- real64 const maxRegionPhaseVolFrac = updateSubRegionState( elemManager, subRegion );
- maxPhaseVolFrac = LvArray::math::max( maxRegionPhaseVolFrac, maxPhaseVolFrac );
- }
- } );
- } );
- maxPhaseVolFrac = MpiWrapper::max( maxPhaseVolFrac );
-
- GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
- GEOS_FMT( " {}: Max well phase volume fraction change = {}",
- getName(), fmt::format( "{:.{}f}", maxPhaseVolFrac, 4 ) ) );
+ real64 maxPhaseVolFrac = updateSubRegionState( elemManager, subRegion );
+ return maxPhaseVolFrac;
}
real64 CompositionalMultiphaseWell::updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion )
{
- // update properties
- updateGlobalComponentFraction( subRegion );
+ real64 maxPhaseVolChange=0.0;
+
+ if( getWellState())
+ {
+
+ // update properties
+ updateGlobalComponentFraction( subRegion );
+
+ // update densities, phase fractions, phase volume fractions
+
+ updateFluidModel( subRegion ); // Calculate fluid properties
+
+ updateSeparator( elemManager, subRegion ); // Calculate fluid properties at control conditions
+
+ updateVolRatesForConstraint( subRegion ); // remove tjb ??
+
+ maxPhaseVolChange = updatePhaseVolumeFraction( subRegion );
+ updateTotalMassDensity( subRegion );
+
+ // Calculate the reference element rates
+ calculateReferenceElementRates( subRegion );
- // update volumetric rates for the well constraints
- // note: this must be called before updateFluidModel
- updateVolRatesForConstraint( elemManager, subRegion );
+ // update the current BHP
+ updateBHPForConstraint( subRegion );
+
+ // Broad case the updated well state to other ranks
+ real64 & currentBHP =
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() );
+ array1d< real64 > currentPhaseVolRate =
+ getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
+ real64 & currentTotalVolRate =
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
+ real64 & currentMassRate =
+ 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() )
+ {
+ getReference< array1d< real64 > >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ) =currentPhaseVolRate;
+
+
+ }
- // update densities, phase fractions, phase volume fractions
- updateFluidModel( subRegion ); // Calculate fluid properties;
- real64 maxPhaseVolChange = updatePhaseVolumeFraction( subRegion );
- updateTotalMassDensity( subRegion );
- // update the current BHP pressure
- updateBHPForConstraint( subRegion );
+ }
return maxPhaseVolChange;
}
-void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, real64 const & time_n )
+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;
+
// TODO: change the way we access the flowSolver here
- CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
+ ElementRegionManager const & elemManager = mesh.getElemManager();
- // loop over the wells
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
- {
+ compositionalMultiphaseWellKernels::PresTempCompFracInitializationKernel::CompFlowAccessors
+ resCompFlowAccessors( elemManager, getFlowSolverName() );
+ compositionalMultiphaseWellKernels::PresTempCompFracInitializationKernel::MultiFluidAccessors
+ resMultiFluidAccessors( elemManager, getFlowSolverName() );
- ElementRegionManager & elemManager = mesh.getElemManager();
- compositionalMultiphaseWellKernels::PresTempCompFracInitializationKernel::CompFlowAccessors
- resCompFlowAccessors( mesh.getElemManager(), flowSolver.getName() );
- compositionalMultiphaseWellKernels::PresTempCompFracInitializationKernel::MultiFluidAccessors
- resMultiFluidAccessors( mesh.getElemManager(), flowSolver.getName() );
+ PerforationData const & perforationData = *subRegion.getPerforationData();
+ arrayView2d< real64 const > const compPerfRate = perforationData.getField< fields::well::compPerforationRate >();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( 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 ));
- bool const hasNonZeroRate = MpiWrapper::max< integer >( hasNonZero( compPerfRate ));
-
- if( wellControls.isWellOpen() && !hasNonZeroRate )
+ if( time_n <= 0.0 || ( isWellOpen( ) && !hasNonZeroRate ) )
+ {
+ setWellState( true );
+ if( getCurrentConstraint() == nullptr )
+ {
+ // tjb needed for backward compatibility. and these 2 lists must be consistent
+ ConstraintTypeId inputControl = ConstraintTypeId( getInputControl());
+ if( isProducer() )
{
- // 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 )
+ forSubGroups< MinimumBHPConstraint, ProductionConstraint< VolumeRateConstraint >, ProductionConstraint< MassRateConstraint >,
+ ProductionConstraint< PhaseVolumeRateConstraint > >( [&]( auto & constraint )
{
- typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
-
- thermalCompositionalMultiphaseBaseKernels::
- FluidUpdateKernel::
- launch< serialPolicy >( subRegion.size(),
- fluidWrapper,
- wellElemPressure,
- wellElemTemp,
- wellElemCompFrac );
+ if( constraint.getControl() == inputControl )
+ {
+ setCurrentConstraint( &constraint );
+ setControl( static_cast< WellControls::Control >(inputControl) ); // tjb old
+ }
+
} );
+ }
+ else
+ {
- compositionalMultiphaseWellKernels::
- CompDensInitializationKernel::launch( subRegion.size(),
- numComp,
- wellElemCompFrac,
- wellElemTotalDens,
- wellElemCompDens );
-
- // 5) Recompute the pressure-dependent properties
- updateSubRegionState( elemManager, subRegion );
-
- // 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 );
+ forSubGroups< MaximumBHPConstraint, InjectionConstraint< VolumeRateConstraint >, InjectionConstraint< MassRateConstraint >,
+ InjectionConstraint< PhaseVolumeRateConstraint > >( [&]( auto & constraint )
+ {
+ if( constraint.getControl() == inputControl )
+ {
+ setCurrentConstraint( &constraint );
+ 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::connectionRate >();
+
+ // 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,
+ *this,
+ 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( elemManager, subRegion );
+
+ // 6) Estimate the well rates
+ // TODO: initialize rates using perforation rates
+ compositionalMultiphaseWellKernels::
+ RateInitializationKernel::
+ launch( subRegion.size(),
+ *this,
+ 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 = getCurrentConstraint();
+ constraint->setBHP ( getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ));
+ constraint->setPhaseVolumeRates ( getReference< array1d< real64 > >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ) );
+ constraint->setTotalVolumeRate ( getReference< real64 >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ));
+ constraint->setMassRate( getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() ));
+ // 7) Copy well / fluid dofs to "prop"_n variables
+ saveState( subRegion );
+ }
+ else if( !hasNonZeroRate )
+ {
+ setWellState( false );
+ GEOS_LOG_RANK_0( "tjb shut wells "<< subRegion.getName());
+ }
+ else
+ {
+ setWellState( true );
+ // setup if restart
+ if( getCurrentConstraint() == nullptr )
+ {
+ updateSubRegionState( elemManager, subRegion );
+ if( isProducer() )
+ {
+ forSubGroups< MinimumBHPConstraint, ProductionConstraint< VolumeRateConstraint >, ProductionConstraint< MassRateConstraint >,
+ ProductionConstraint< PhaseVolumeRateConstraint > >( [&](
+ auto
+ & constraint )
+ {
+ if( ConstraintTypeId( getControl()) == constraint.getControl() )
+ {
+ setCurrentConstraint( &constraint );
+ }
+ } );
+ }
+ else
+ {
+ forSubGroups< MaximumBHPConstraint, InjectionConstraint< VolumeRateConstraint >, InjectionConstraint< MassRateConstraint >, InjectionConstraint< PhaseVolumeRateConstraint > >( [&](
+ auto
+ &
+ constraint )
+ {
+ if( ConstraintTypeId( getControl()) == constraint.getControl() )
+ {
+ setCurrentConstraint( &constraint );
+ }
+ } );
+ }
+ }
+
+ }
}
-void CompositionalMultiphaseWell::assembleFluxTerms( real64 const & time,
- real64 const & dt,
- DomainPartition & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs )
+
+
+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 );
@@ -1178,62 +1167,55 @@ void CompositionalMultiphaseWell::assembleFluxTerms( real64 const & time,
kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation );
string const wellDofKey = dofManager.getKey( wellElementDofName());
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+
+
+ if( isWellOpen( ) && !m_keepVariablesConstantDuringInitStep )
{
- mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString());
+ MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
+ int numComponents = fluid.numFluidComponents();
+
+ if( isThermal() )
{
- 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();
+ thermalCompositionalMultiphaseWellKernels::
+ FaceBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( numComponents,
+ dt,
+ dofManager.rankOffset(),
+ kernelFlags,
+ wellDofKey,
+ *this,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+ else
+ {
+ compositionalMultiphaseWellKernels::
+ FaceBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( numComponents,
+ dt,
+ dofManager.rankOffset(),
+ kernelFlags,
+ wellDofKey,
+ *this,
+ subRegion,
+ localMatrix,
+ localRhs );
+ }
+ }
- 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 );
- }
- }
- } );
- } );
}
-void CompositionalMultiphaseWell::assembleAccumulationTerms( real64 const & time,
- real64 const & dt,
- DomainPartition & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & 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 );
@@ -1244,123 +1226,124 @@ void CompositionalMultiphaseWell::assembleAccumulationTerms( real64 const & time
kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation );
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 = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
+ integer const numPhases = fluid.numFluidPhases();
+ integer const numComponents = fluid.numFluidComponents();
+
+ if( getWellStatus() == WellControls::Status::OPEN && !m_keepVariablesConstantDuringInitStep )
{
- mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
+ if( isThermal() )
+ {
+
+ thermalCompositionalMultiphaseWellKernels::
+ ElementBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( numComponents,
+ numPhases,
+ isProducer(),
+ dofManager.rankOffset(),
+ kernelFlags,
+ wellDofKey,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+ else
{
- 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 )
+ compositionalMultiphaseWellKernels::
+ ElementBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( numComponents,
+ numPhases,
+ 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::connectionRate >();
+ localIndex rank_offset = dofManager.rankOffset();
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ {
+ if( wellElemGhostRank[ei] < 0 )
{
- if( isThermal() )
+ if( elemStatus[ei]==WellElementSubRegion::WellElemStatus::CLOSED )
{
+ mixConnRate[ei] = 0.0;
+ globalIndex const dofIndex = wellElemDofNumber[ei];
+ localIndex const localRow = dofIndex - rank_offset;
- 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 )
+ real64 const unity = 1.0;
+ for( integer i=0; i < m_numDofPerWellElement; i++ )
{
- 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;
- }
- }
+ globalIndex const rindex = localRow+i;
+ globalIndex const cindex =dofIndex + i;
+ localMatrix.template addToRow< serialAtomic >( rindex,
+ &cindex,
+ &unity,
+ 1 );
+ localRhs[rindex] = 0.0;
}
- } );
+ }
}
- else
+ } );
+
+ }
+ 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::connectionRate >();
+ localIndex rank_offset = dofManager.rankOffset();
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ {
+ if( wellElemGhostRank[ei] < 0 )
{
- // 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 )
+ 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++ )
{
- 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;
- }
- }
- } );
+ globalIndex const rindex = localRow+i;
+ globalIndex const cindex =dofIndex + i;
+ localMatrix.template addToRow< serialAtomic >( rindex,
+ &cindex,
+ &unity,
+ 1 );
+ localRhs[rindex] = 0.0;
+ }
}
- } ); // forElementSubRegions
- } ); // forDiscretizationOnMeshTargets
+ } );
+ // zero out current state constraint quantities
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() )=0.0;
+ getReference< array1d< real64 > >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ).zero();
+ getReference< real64 >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() )=0.0;
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() )=0.0;
+ }
}
-
-real64
-CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n,
- real64 const & dt,
- DomainPartition const & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localRhs )
+array1d< real64 >
+CompositionalMultiphaseWell::calculateLocalWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ NonlinearSolverParameters const & nonlinearSolverParameters,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs )
{
GEOS_MARK_FUNCTION;
@@ -1371,93 +1354,127 @@ CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n,
globalIndex const rankOffset = dofManager.rankOffset();
string const wellDofKey = dofManager.getKey( wellElementDofName() );
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel const & mesh,
- string_array const & regionNames )
+
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
+
+
+ // step 1: compute the norm in the subRegion
+
+ if( !isWellOpen() )
+ {
+ for( integer i = 0; i < numNorm; ++i )
+ {
+ localResidualNorm[i] = 0.0;
+ localResidualNormalizer[i] = nonlinearSolverParameters.m_minNormalizer;
+ }
+ }
+ else if( isThermal() )
+ {
+ real64 subRegionResidualNorm[2]{};
+
+ thermalCompositionalMultiphaseWellKernels::ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ *this,
+ time_n,
+ dt,
+ 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]{};
+ compositionalMultiphaseWellKernels::ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ m_numDofPerWellElement,
+ rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ *this,
+ time_n,
+ dt,
+ nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
- ElementRegionManager const & elemManager = mesh.getElemManager();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion const & subRegion )
+ // step 2: reduction across meshBodies/regions/subRegions
+
+ if( subRegionResidualNorm[0] > localResidualNorm[0] )
{
+ localResidualNorm[0] = subRegionResidualNorm[0];
+ }
+ }
+ return localResidualNorm;
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
+}
- WellControls const & wellControls = getWellControls( subRegion );
+real64
+CompositionalMultiphaseWell::calculateWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ NonlinearSolverParameters const & nonlinearSolverParameters,
+ 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;
- // step 1: compute the norm in the subRegion
+ if( isThermal() )
+ {
+ numNorm = 2; // mass balance and energy balance
+ }
+ localResidualNorm.resize( numNorm );
+ localResidualNormalizer.resize( numNorm );
- if( !wellControls.isWellOpen() )
- {
- for( integer i = 0; i < numNorm; ++i )
- {
- localResidualNorm[i] = 0.0;
- localResidualNormalizer[i] = m_nonlinearSolverParameters.m_minNormalizer;
- }
- }
- else if( isThermal() )
- {
- real64 subRegionResidualNorm[2]{};
-
- thermalCompositionalMultiphaseWellKernels::ResidualNormKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( 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
-
- 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 );
-
-
-
- // step 2: reduction across meshBodies/regions/subRegions
-
- if( subRegionResidualNorm[0] > localResidualNorm[0] )
- {
- localResidualNorm[0] = subRegionResidualNorm[0];
- }
- }
- } );
- } );
+ //globalIndex const rankOffset = dofManager.rankOffset();
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+
+
+
+ //string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ //MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
+
+ if( isWellOpen( ) )
+ {
+ localResidualNorm = calculateLocalWellResidualNorm( time_n,
+ dt,
+ nonlinearSolverParameters,
+ subRegion,
+ dofManager,
+ localRhs );
+ }
+ else
+ {
+ for( integer i=0; i const & localSolution )
+{
+ GEOS_MARK_FUNCTION;
+
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+
+ real64 scalingFactor = 1.0;
+ maxDeltaPres = 0.0;
+ maxDeltaCompDens = 0.0;
+ maxDeltaTemp = 0.0;
+ 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 resNorm;
-}
+ return LvArray::math::max( scalingFactor, m_minScalingFactor );
+
+}
real64
-CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution )
+CompositionalMultiphaseWell::scalingForWellSystemSolution( WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution )
{
GEOS_MARK_FUNCTION;
@@ -1497,76 +1628,15 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain,
real64 maxDeltaPres = 0.0, maxDeltaCompDens = 0.0, maxDeltaTemp = 0.0;
real64 minPresScalingFactor = 1.0, minCompDensScalingFactor = 1.0, minTempScalingFactor = 1.0;
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
- {
- mesh.getElemManager().forElementSubRegions( regionNames,
- [&]( localIndex const,
- ElementSubRegionBase & subRegion )
- {
- 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 >();
- 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 );
-
+ scalingForLocalSystemSolution( subRegion,
+ dofManager,
+ maxDeltaPres,
+ maxDeltaCompDens,
+ maxDeltaTemp,
+ minPresScalingFactor,
+ minCompDensScalingFactor,
+ minTempScalingFactor,
+ localSolution );
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)",
@@ -1584,7 +1654,6 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain,
getName(), GEOS_FMT( "{:.{}f}", maxDeltaTemp, 3 ) ) );
}
-
GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
GEOS_FMT( " {}: Min well pressure scaling factor: {}",
getName(), minPresScalingFactor ) );
@@ -1598,94 +1667,90 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain,
getName(), minTempScalingFactor ) );
}
-
return LvArray::math::max( scalingFactor, m_minScalingFactor );
}
+
+
bool
-CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution,
- real64 const scalingFactor )
+CompositionalMultiphaseWell::checkWellSystemSolution( WellElementSubRegion & 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 );
-
- 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;
- } );
- } );
+ 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 );
@@ -1697,103 +1762,98 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain,
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 ) ) );
+ 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: {} {} ",
- getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) );
+ 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: {} {} ",
- getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) );
+ subRegion.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 ),
- DomainPartition & domain )
+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 );
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+ //CompositionalMultiphaseBase const & flowSolver = getParent().getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
+
+ PerforationData * const perforationData = subRegion.getPerforationData();
+
+ if( isWellOpen() && !m_keepVariablesConstantDuringInitStep )
{
- // TODO: change the way we access the flowSolver here
- CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
- ElementRegionManager & elemManager = mesh.getElemManager();
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
+ bool isThermal = fluid.isThermal();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
- WellElementSubRegion & subRegion )
+ if( isThermal )
{
- 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();
-
- 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
+ thermalPerforationFluxKernels::
+ PerforationFluxKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ m_numPhases,
+ getFlowSolverName(),
+ perforationData,
+ subRegion,
+ fluid,
+ elemManager,
+ isInjector(),
+ isCrossflowEnabled());
+ }
+ else
+ {
+ isothermalPerforationFluxKernels::
+ PerforationFluxKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ m_numPhases,
+ getFlowSolverName(),
+ perforationData,
+ subRegion,
+ elemManager,
+ isInjector(),
+ 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 )
{
- // 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;
- }
- }
+ compPerfRate[iperf][ic] = 0.0;
}
- } );
+ }
+ }
- } );
}
+
void
-CompositionalMultiphaseWell::applySystemSolution( DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution,
- real64 const scalingFactor,
- real64 const dt,
- DomainPartition & domain )
+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 );
@@ -1801,513 +1861,585 @@ CompositionalMultiphaseWell::applySystemSolution( DofManager const & dofManager,
// update all the fields using the global damping coefficients
dofManager.addVectorToField( localSolution,
wellElementDofName(),
- well::pressure::key(),
+ fields::well::pressure::key(),
scalingFactor,
pressureMask );
dofManager.addVectorToField( localSolution,
wellElementDofName(),
- well::globalCompDensity::key(),
+ fields::well::globalCompDensity::key(),
scalingFactor,
componentMask );
dofManager.addVectorToField( localSolution,
wellElementDofName(),
- well::mixtureConnectionRate::key(),
+ fields::well::connectionRate::key(),
scalingFactor,
connRateMask );
if( isThermal() )
{
DofManager::CompMask temperatureMask( m_numDofPerWellElement, numFluidComponents()+2, numFluidComponents()+3 );
-
dofManager.addVectorToField( localSolution,
wellElementDofName(),
- well::temperature::key(),
+ fields::well::temperature::key(),
scalingFactor,
temperatureMask );
}
+
// if component density chopping is allowed, some component densities may be negative after the update
// these negative component densities are set to zero in this function
if( m_allowCompDensChopping )
{
- chopNegativeDensities( domain );
+ chopNegativeDensities( subRegion );
}
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+ // synchronize
+ FieldIdentifiers fieldsToBeSync;
+ if( isThermal() )
{
- // synchronize
- FieldIdentifiers fieldsToBeSync;
- if( isThermal() )
- {
- fieldsToBeSync.addElementFields( { well::pressure::key(),
- well::globalCompDensity::key(),
- well::mixtureConnectionRate::key(),
- well::temperature::key() },
- regionNames );
- }
- else
- {
- fieldsToBeSync.addElementFields( { well::pressure::key(),
- well::globalCompDensity::key(),
- well::mixtureConnectionRate::key() },
- regionNames );
- }
- CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync,
- mesh,
- domain.getNeighbors(),
- true );
- } );
-
+ fieldsToBeSync.addElementFields( { fields::well::pressure::key(),
+ fields::well::globalCompDensity::key(),
+ fields::well::connectionRate::key(),
+ fields::well::temperature::key() },
+ getTargetRegionNames() );
+ }
+ else
+ {
+ fieldsToBeSync.addElementFields( { fields::well::pressure::key(),
+ fields::well::globalCompDensity::key(),
+ fields::well::connectionRate::key() },
+ getTargetRegionNames() );
+ }
+ CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync,
+ mesh,
+ domain.getNeighbors(),
+ true );
}
-void CompositionalMultiphaseWell::chopNegativeDensities( DomainPartition & domain )
+
+
+void CompositionalMultiphaseWell::chopNegativeDensities( WellElementSubRegion & subRegion )
{
integer const numComp = m_numComponents;
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
- {
-
- ElementRegionManager & elemManager = mesh.getElemManager();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
- {
- arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank();
+ arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank();
- arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens =
- subRegion.getField< well::globalCompDensity >();
+ arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens =
+ subRegion.getField< fields::well::globalCompDensity >();
- forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
+ {
+ if( wellElemGhostRank[iwelem] < 0 )
+ {
+ for( integer ic = 0; ic < numComp; ++ic )
{
- if( wellElemGhostRank[iwelem] < 0 )
+ // 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 )
{
- 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;
- }
- }
+ wellElemCompDens[iwelem][ic] = 0.0;
}
- } );
- } );
-
+ }
+ }
} );
+
}
-void CompositionalMultiphaseWell::resetStateToBeginningOfStep( DomainPartition & domain )
+void CompositionalMultiphaseWell::resetStateToBeginningOfStep( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion )
{
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+
+ // get a reference to the primary variables on well elements
+ arrayView1d< real64 > const & wellElemPressure =
+ subRegion.getField< well::pressure >();
+ arrayView1d< real64 const > const & wellElemPressure_n =
+ subRegion.getField< well::pressure_n >();
+ wellElemPressure.setValues< parallelDevicePolicy<> >( wellElemPressure_n );
+
+ if( isThermal() )
+ {
+ // get a reference to the primary variables on well elements
+ arrayView1d< real64 > const & wellElemTemperature =
+ subRegion.getField< well::temperature >();
+ arrayView1d< real64 const > const & wellElemTemperature_n =
+ subRegion.getField< well::temperature_n >();
+ wellElemTemperature.setValues< parallelDevicePolicy<> >( wellElemTemperature_n );
+ }
+ arrayView2d< real64, compflow::USD_COMP > const & wellElemGlobalCompDensity =
+ subRegion.getField< well::globalCompDensity >();
+ arrayView2d< real64 const, compflow::USD_COMP > const & wellElemGlobalCompDensity_n =
+ subRegion.getField< well::globalCompDensity_n >();
+ wellElemGlobalCompDensity.setValues< parallelDevicePolicy<> >( wellElemGlobalCompDensity_n );
+
+ arrayView1d< real64 > const & connRate =
+ subRegion.getField< well::connectionRate >();
+ arrayView1d< real64 const > const & connRate_n =
+ subRegion.getField< well::connectionRate_n >();
+ connRate.setValues< parallelDevicePolicy<> >( connRate_n );
+
+
+ if( isWellOpen( ) )
{
+ updateSubRegionState( elemManager, subRegion );
+ }
+
+}
+
+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.
- ElementRegionManager & elemManager = mesh.getElemManager();
+ if( !subRegion.isLocallyOwned() || !( getWellStatus() == WellControls::Status::OPEN ))
+ {
+ return;
+ }
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
+ if( isProducer() )
+ {
+ forSubGroups< MinimumBHPConstraint, ProductionConstraint< PhaseVolumeRateConstraint >, ProductionConstraint< MassRateConstraint >, ProductionConstraint< VolumeRateConstraint >,
+ ProductionConstraint< LiquidRateConstraint >
+ >( [&]( auto & constraint )
{
- // get a reference to the primary variables on well elements
- arrayView1d< real64 > const & wellElemPressure =
- subRegion.getField< well::pressure >();
- arrayView1d< real64 const > const & wellElemPressure_n =
- subRegion.getField< well::pressure_n >();
- wellElemPressure.setValues< parallelDevicePolicy<> >( wellElemPressure_n );
-
- if( isThermal() )
+ // Need to use name since there could be multiple constraints of the same type
+ if( constraint.getName() == getCurrentConstraint()->getName())
{
- // get a reference to the primary variables on well elements
- arrayView1d< real64 > const & wellElemTemperature =
- subRegion.getField< well::temperature >();
- arrayView1d< real64 const > const & wellElemTemperature_n =
- subRegion.getField< well::temperature_n >();
- wellElemTemperature.setValues< parallelDevicePolicy<> >( wellElemTemperature_n );
+ // found limiting constraint
+ constitutive::MultiFluidBase & fluidSeparator = 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,
+ *this,
+ constraint,
+ subRegion,
+ dofManager.getKey( wellElementDofName() ),
+ dofManager.rankOffset(),
+ localMatrix,
+ localRhs );
+ } );
}
- arrayView2d< real64, compflow::USD_COMP > const & wellElemGlobalCompDensity =
- subRegion.getField< well::globalCompDensity >();
- arrayView2d< real64 const, compflow::USD_COMP > const & wellElemGlobalCompDensity_n =
- subRegion.getField< well::globalCompDensity_n >();
- wellElemGlobalCompDensity.setValues< parallelDevicePolicy<> >( wellElemGlobalCompDensity_n );
-
- arrayView1d< real64 > const & connRate =
- subRegion.getField< well::mixtureConnectionRate >();
- arrayView1d< real64 const > const & connRate_n =
- subRegion.getField< well::mixtureConnectionRate_n >();
- connRate.setValues< parallelDevicePolicy<> >( connRate_n );
- WellControls & wellControls = getWellControls( subRegion );
-
- if( wellControls.isWellOpen( ) )
+ } );
+ }
+ else
+ {
+ forSubGroups< MaximumBHPConstraint, InjectionConstraint< PhaseVolumeRateConstraint >, InjectionConstraint< MassRateConstraint >,
+ InjectionConstraint< VolumeRateConstraint >,
+ InjectionConstraint< LiquidRateConstraint >
+ >( [&]( auto & constraint )
+ {
+ if( constraint.getName() == getCurrentConstraint()->getName())
{
- updateSubRegionState( elemManager, subRegion );
+ // found limiting constraint
+ constitutive::MultiFluidBase & fluidSeparator = 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,
+ *this,
+ constraint,
+ subRegion,
+ dofManager.getKey( wellElementDofName() ),
+ dofManager.rankOffset(),
+ localMatrix,
+ localRhs );
+ } );
}
} );
- } );
+ }
}
-void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time_n,
- real64 const & GEOS_UNUSED_PARAM( dt ),
- DomainPartition const & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & 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;
- forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel const & mesh,
- string_array const & regionNames )
+ if( 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 );
- ElementRegionManager const & elemManager = mesh.getElemManager();
+ }
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion const & subRegion )
- {
+}
- 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(),
- 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::connectionRate >();
+ arrayView1d< real64 > const & connRate_n =
+ subRegion.getField< fields::well::connectionRate_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,
real64 const & dt,
- DomainPartition & domain )
+ ElementRegionManager & elemManager,
+ WellElementSubRegion & subRegion )
{
- WellSolverBase::implicitStepSetup( time_n, dt, domain );
+ WellControls::implicitStepSetup( time_n, dt, elemManager, subRegion );
- forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+ if( isWellOpen() )
{
+ // 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 );
- ElementRegionManager & elemManager = mesh.getElemManager();
-
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
+ if( isThermal() )
{
+ arrayView1d< real64 > const & wellElemTemperature_n =
+ subRegion.getField< fields::well::temperature_n >();
+ wellElemTemperature_n.setValues< parallelDevicePolicy<> >( wellElemTemperature );
+ }
- WellControls & wellControls = getWellControls( subRegion );
- if( wellControls.isWellOpen() )
- {
- // 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 );
- 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::connectionRate >();
+ arrayView1d< real64 > const & connRate_n =
+ subRegion.getField< fields::well::connectionRate_n >();
+ connRate_n.setValues< parallelDevicePolicy<> >( connRate );
- 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 );
- 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();
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
- fluid.saveConvergedState();
+ validateWellConstraints( time_n, dt, subRegion );
- validateWellConstraints( time_n, dt, subRegion );
+ updateSubRegionState( elemManager, subRegion );
+ }
- updateSubRegionState( elemManager, subRegion );
- }
- } )
- ;
- } );
}
void CompositionalMultiphaseWell::implicitStepComplete( real64 const & time_n,
real64 const & dt,
- DomainPartition & domain )
+ WellElementSubRegion const & subRegion )
{
- WellSolverBase::implicitStepComplete( time_n, dt, domain );
-
- if( getLogLevel() > 0 )
- {
- printRates( time_n, dt, domain );
- }
+ printRates( time_n, dt, subRegion );
}
void CompositionalMultiphaseWell::printRates( real64 const & time_n,
real64 const & dt,
- DomainPartition & domain )
+ WellElementSubRegion const & subRegion )
{
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
- {
- ElementRegionManager & elemManager = mesh.getElemManager();
+ integer const numPhase = m_numPhases;
+ integer const numComp = m_numComponents;
+ integer const numPerf = subRegion.getPerforationData()->size();
+
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
- {
- integer const numPhase = m_numPhases;
- integer const numComp = m_numComponents;
- integer const numPerf = subRegion.getPerforationData()->size();
- // control data
- WellControls const & wellControls = getWellControls( subRegion );
+ stdVector< double > compRate( numComp, 0.0 );
+ if( m_writeCSV > 0 && isWellOpen( ) )
+ {
+ arrayView2d< real64 const > const & compPerfRate = subRegion.getPerforationData()->getField< fields::well::compPerforationRate >();
- stdVector< double > compRate( numComp, 0.0 );
- if( m_writeCSV > 0 && wellControls.isWellOpen( ) )
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [&numComp,
+ &numPerf,
+ compPerfRate,
+ &compRate] ( localIndex const )
+ {
+ for( integer ic = 0; ic < numComp; ++ic )
{
- arrayView2d< real64 > const compPerfRate = subRegion.getPerforationData()->getField< fields::well::compPerforationRate >();
-
- // bring everything back to host, capture the scalars by reference
- forAll< serialPolicy >( 1, [&numComp,
- &numPerf,
- compPerfRate,
- &compRate] ( localIndex const )
+ for( integer iperf = 0; iperf < numPerf; iperf++ )
{
- for( integer ic = 0; ic < numComp; ++ic )
- {
- for( integer iperf = 0; iperf < numPerf; iperf++ )
- {
- compRate[ic] += compPerfRate[iperf][ic];
- }
- }
- } );
- for( integer ic = 0; ic < numComp; ++ic )
- {
- compRate[ic] = MpiWrapper::sum( compRate[ic] );
+ compRate[ic] += compPerfRate[iperf][ic];
}
}
+ } );
+ for( integer ic = 0; ic < numComp; ++ic )
+ {
+ compRate[ic] = MpiWrapper::sum( compRate[ic] );
+ }
+ }
- // the rank that owns the reference well element is responsible for the calculations below.
- if( !subRegion.isLocallyOwned() )
+ // the rank that owns the reference well element is responsible for the calculations below.
+ if( !subRegion.isLocallyOwned() )
+ {
+ return;
+ }
+
+ string const wellControlsName = getName();
+
+ // format: time,total_rate,total_vol_rate,phase0_vol_rate,phase1_vol_rate,...
+ std::ofstream outputFile;
+ if( m_writeCSV > 0 )
+ {
+ outputFile.open( m_ratesOutputDir + "/" + wellControlsName + ".csv", std::ios_base::app );
+ outputFile << time_n << "," << dt;
+ }
+
+ if( getWellStatus() == WellControls::Status::CLOSED )
+ {
+ GEOS_LOG( GEOS_FMT( "{}: well is shut", wellControlsName ) );
+ if( outputFile.is_open())
+ {
+ // print all zeros in the rates file
+ outputFile << ",0.0,0.0,0.0";
+ for( integer ip = 0; ip < numPhase; ++ip )
{
- return;
+ outputFile << ",0.0";
}
+ for( integer ic = 0; ic < numComp; ++ic )
+ {
+ outputFile << ",0.0";
+ }
+ outputFile << std::endl;
+ outputFile.close();
+ }
+ return;
+ }
+
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+ string const massUnit = m_useMass ? "kg" : "mol";
- string const wellControlsName = wellControls.getName();
+ // subRegion data
- // format: time,total_rate,total_vol_rate,phase0_vol_rate,phase1_vol_rate,...
- std::ofstream outputFile;
- if( m_writeCSV > 0 )
+ arrayView1d< real64 const > const & connRate =
+ subRegion.getField< well::connectionRate >();
+
+ integer const useSurfaceCond = useSurfaceConditions();
+
+ real64 const & currentBHP =
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() );
+ arrayView1d< real64 const > const & currentPhaseVolRate =
+ getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
+ real64 const & currentTotalVolRate =
+ getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [&numPhase,
+ &numComp,
+ &useSurfaceCond,
+ ¤tBHP,
+ connRate,
+ ¤tTotalVolRate,
+ currentPhaseVolRate,
+ &compRate,
+ &iwelemRef,
+ &wellControlsName,
+ &massUnit,
+ &outputFile] ( localIndex const )
+ {
+ string const conditionKey = useSurfaceCond ? "surface" : "reservoir";
+ string const unitKey = useSurfaceCond ? "s" : "r";
+
+ real64 const currentTotalRate = connRate[iwelemRef];
+ GEOS_LOG( GEOS_FMT( "{}: BHP (at the specified reference elevation): {} Pa",
+ wellControlsName, currentBHP ) );
+ GEOS_LOG( GEOS_FMT( "{}: Total rate: {} {}/s; total {} volumetric rate: {} {}m3/s",
+ wellControlsName, currentTotalRate, massUnit, conditionKey, currentTotalVolRate, unitKey ) );
+ for( integer ip = 0; ip < numPhase; ++ip )
+ GEOS_LOG( GEOS_FMT( "{}: Phase {} {} volumetric rate: {} {}m3/s",
+ wellControlsName, ip, conditionKey, currentPhaseVolRate[ip], unitKey ) );
+ if( outputFile.is_open())
+ {
+ outputFile << "," << currentBHP;
+ outputFile << "," << currentTotalRate << "," << currentTotalVolRate;
+ for( integer ip = 0; ip < numPhase; ++ip )
{
- outputFile.open( m_ratesOutputDir + "/" + wellControlsName + ".csv", std::ios_base::app );
- outputFile << time_n << "," << dt;
+ outputFile << "," << currentPhaseVolRate[ip];
}
-
- if( wellControls.getWellStatus() == WellControls::Status::CLOSED )
+ for( integer ic = 0; ic < numComp; ++ic )
{
- GEOS_LOG( GEOS_FMT( "{}: well is shut", wellControlsName ) );
- if( outputFile.is_open())
- {
- // print all zeros in the rates file
- outputFile << ",0.0,0.0,0.0";
- for( integer ip = 0; ip < numPhase; ++ip )
- {
- outputFile << ",0.0";
- }
- for( integer ic = 0; ic < numComp; ++ic )
- {
- outputFile << ",0.0";
- }
- outputFile << std::endl;
- outputFile.close();
- }
- return;
+ outputFile << "," << compRate[ic];
}
+ outputFile << std::endl;
+ outputFile.close();
+ }
+ } );
+
+}
+
+
+bool CompositionalMultiphaseWell::evaluateConstraints( real64 const & time_n,
+ WellElementSubRegion & subRegion )
+{
+
+ // create list of all constraints to process
+ std::vector< WellConstraintBase * > constraintList;
+ if( isProducer() )
+ {
+ constraintList = getProdRateConstraints();
+ // Solve minimum bhp constraint first
+ constraintList.insert( constraintList.begin(), getMinBHPConstraint() );
+ }
+ else
+ {
+ constraintList = getInjRateConstraints();
+ // Solve maximum bhp constraint first;
+ constraintList.insert( constraintList.begin(), getMaxBHPConstraint() );
+ }
+ // Get current constraint
+ WellConstraintBase * limitingConstraint = nullptr;
+ for( auto & constraint : constraintList )
+ {
+ if( constraint->getName() == getCurrentConstraint()->getName())
+ {
+ limitingConstraint = constraint;
+ // tjb. this is likely not needed. set in update state
+ constraint->setBHP ( getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ));
+ constraint->setPhaseVolumeRates ( getReference< array1d< real64 > >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ) );
+ constraint->setTotalVolumeRate ( getReference< real64 >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ));
+ constraint->setMassRate( 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());
+ }
+ }
+ constraintList.erase( std::find( constraintList.begin(), constraintList.end(), limitingConstraint ) );
+
+ // Check current against other constraints
+ for( auto & constraint : constraintList )
+ {
- localIndex const iwelemRef = subRegion.getTopWellElementIndex();
- string const massUnit = m_useMass ? "kg" : "mol";
-
- // subRegion data
-
- arrayView1d< real64 const > const & connRate =
- subRegion.getField< well::mixtureConnectionRate >();
-
- integer const useSurfaceConditions = wellControls.useSurfaceConditions();
-
- real64 const & currentBHP =
- wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() );
- arrayView1d< real64 const > const & currentPhaseVolRate =
- wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
- real64 const & currentTotalVolRate =
- wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
-
- // bring everything back to host, capture the scalars by reference
- forAll< serialPolicy >( 1, [&numPhase,
- &numComp,
- &useSurfaceConditions,
- ¤tBHP,
- connRate,
- ¤tTotalVolRate,
- currentPhaseVolRate,
- &compRate,
- &iwelemRef,
- &wellControlsName,
- &massUnit,
- &outputFile] ( localIndex const )
+ if( limitingConstraint->getName() != constraint->getName())
+ {
+ if( constraint->checkViolation( *limitingConstraint, time_n ) )
{
- string const conditionKey = useSurfaceConditions ? "surface" : "reservoir";
- string const unitKey = useSurfaceConditions ? "s" : "r";
-
- real64 const currentTotalRate = connRate[iwelemRef];
- GEOS_LOG( GEOS_FMT( "{}: BHP (at the specified reference elevation): {} Pa",
- wellControlsName, currentBHP ) );
- GEOS_LOG( GEOS_FMT( "{}: Total rate: {} {}/s; total {} volumetric rate: {} {}m3/s",
- wellControlsName, currentTotalRate, massUnit, conditionKey, currentTotalVolRate, unitKey ) );
- for( integer ip = 0; ip < numPhase; ++ip )
- GEOS_LOG( GEOS_FMT( "{}: Phase {} {} volumetric rate: {} {}m3/s",
- wellControlsName, ip, conditionKey, currentPhaseVolRate[ip], unitKey ) );
- if( outputFile.is_open())
- {
- outputFile << "," << currentBHP;
- outputFile << "," << currentTotalRate << "," << currentTotalVolRate;
- for( integer ip = 0; ip < numPhase; ++ip )
- {
- outputFile << "," << currentPhaseVolRate[ip];
- }
- for( integer ic = 0; ic < numComp; ++ic )
- {
- outputFile << "," << compRate[ic];
- }
- outputFile << std::endl;
- outputFile.close();
- }
- } );
- } );
- } );
+ limitingConstraint = constraint;
+ setControl( static_cast< WellControls::Control >(constraint->getControl()) ); // tjb old
+ setCurrentConstraint( constraint );
+ constraint->setBHP ( getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ));
+ constraint->setPhaseVolumeRates ( getReference< array1d< real64 > >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ) );
+ constraint->setTotalVolumeRate ( getReference< real64 >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ));
+ constraint->setMassRate( getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() ));
+ GEOS_LOG_RANK_IF ( subRegion.isLocallyOwned(),
+ " Well " << subRegion.getName() << " Control switch " << 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 cb8ed9f1a6f..6ee60202255 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp
@@ -22,9 +22,11 @@
#include "constitutive/fluid/multifluid/Layouts.hpp"
#include "constitutive/relativePermeability/Layouts.hpp"
-#include "physicsSolvers/fluidFlow/wells/WellSolverBase.hpp"
+
#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellConstraintsBase.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
namespace geos
{
@@ -39,7 +41,7 @@ class MultiFluidBase;
*
* A compositional multiphase well solver
*/
-class CompositionalMultiphaseWell : public WellSolverBase
+class CompositionalMultiphaseWell : public WellControls
{
public:
@@ -57,8 +59,8 @@ class CompositionalMultiphaseWell : public WellSolverBase
/// deleted copy constructor
CompositionalMultiphaseWell( CompositionalMultiphaseWell const & ) = delete;
- /// default move constructor
- CompositionalMultiphaseWell( CompositionalMultiphaseWell && ) = default;
+ /// deleted move constructor
+ CompositionalMultiphaseWell( CompositionalMultiphaseWell && ) = delete;
/// deleted assignment operator
CompositionalMultiphaseWell & operator=( CompositionalMultiphaseWell const & ) = delete;
@@ -71,64 +73,164 @@ class CompositionalMultiphaseWell : public WellSolverBase
*/
virtual ~CompositionalMultiphaseWell() override = default;
+
+ virtual void registerWellDataOnMesh( WellElementSubRegion & subRegion ) override;
/**
- * @brief name of the node manager in the object catalog
- * @return string that contains the catalog name to generate a new NodeManager object through the object catalog.
+ * @defgroup WellManager Interface Functions
+ *
+ * These functions provide the primary interface that is required for derived classes
+ * The "Well" versions apply to individual well subRegions, whereas the others apply to all wells
*/
- static string catalogName() { return "CompositionalMultiphaseWell"; }
+ /**@{*/
/**
- * @copydoc PhysicsSolverBase::getCatalogName()
+ * * @brief Initialize well for the beginning of a simulation or restart
+ * @param domain the domain
+ * @param mesh the mesh level
+ * @param subRegion the well subRegion
*/
- string getCatalogName() const override { return catalogName(); }
+ virtual void initializeWell( DomainPartition & domain, MeshLevel & mesh, WellElementSubRegion & subRegion, real64 const & time_n )override;
- virtual void registerDataOnMesh( Group & meshBodies ) override;
+ /**
+ * @brief Function to evaluate well constraints after applying the solution update
+ * @param time_n the time at the beginning of the time step
+ * @param subRegion the well subRegion
+ * @return true if all constraints are satisfied, false otherwise
+ */
+ virtual bool evaluateConstraints( real64 const & time_n,
+ WellElementSubRegion & subRegion ) override;
+ /**
+ * @copydoc WellControls::assembleWellAccumulationTerms()
+ */
+ 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;
+ /**
+ * @copydoc WellControls::assembleWellPressureRelations()
+ */
+ 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;
+ /**
+ * @copydoc WellControls::assembleWellConstraintTerms()
+ */
+ 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;
+ /**
+ * @copydoc WellControls::computeWellPerforationRates()
+ */
+ virtual void computeWellPerforationRates( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager const & elemManager,
+ WellElementSubRegion & subRegion ) override;
/**
- * @defgroup Solver Interface Functions
+ * @copydoc WellControls::assembleFluxTerms()
+ */
+ 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;
+ /**@}*/
+ /**
+ * @defgroup Well Interface Functions - required by WellManager and WellNewtonSolver
*
* These functions provide the primary interface that is required for derived classes
+ * The "Well" versions apply to individual well subRegions
*/
/**@{*/
+ /**
+ * @copydoc WellControls::calculateResidualNorm()
+ */
+
+ virtual array1d< real64 >
+ calculateLocalWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ NonlinearSolverParameters const & nonlinearSolverParameters,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs )override;
- virtual real64
- calculateResidualNorm( real64 const & time_n,
- real64 const & dt,
- DomainPartition const & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localRhs ) override;
virtual real64
- scalingForSystemSolution( DomainPartition & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution ) override;
+ calculateWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ NonlinearSolverParameters const & nonlinearSolverParameters,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs ) override;
+
+ /**
+ * @copydoc WellControls::scalingForSystemSolution()
+ */
+ real64 scalingForLocalSystemSolution ( WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ real64 & maxDeltaPres,
+ real64 & maxDeltaCompDens,
+ real64 & maxDeltaTemp,
+ real64 & minPresScalingFactor,
+ real64 & minCompDensScalingFactor,
+ real64 & minTempScalingFactor,
+ arrayView1d< real64 const > const & localSolution );
+
+ virtual real64 scalingForWellSystemSolution( WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution ) override;
+ /**
+ * @copydoc WellControls::checkSystemSolution()
+ */
virtual bool
- checkSystemSolution( DomainPartition & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution,
- real64 const scalingFactor ) override;
+ checkWellSystemSolution( WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor ) override;
- virtual void
- applySystemSolution( DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution,
- real64 const scalingFactor,
- real64 const dt,
- DomainPartition & domain ) override;
+ /**
+ * @copydoc WellControls::applyWellSystemSolution()
+ */
virtual void
- resetStateToBeginningOfStep( DomainPartition & domain ) override;
+ applyWellSystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain,
+ MeshLevel & mesh,
+ WellElementSubRegion & subRegion ) override;
- virtual void
- implicitStepSetup( real64 const & time,
- real64 const & dt,
- DomainPartition & domain ) override;
+ virtual void resetStateToBeginningOfStep( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override;
+
+ virtual void implicitStepSetup( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager & elemManager,
+ WellElementSubRegion & subRegion )override;
virtual void
implicitStepComplete( real64 const & time,
real64 const & dt,
- DomainPartition & domain ) override;
+ WellElementSubRegion const & subRegion ) override;
+
+ virtual void initializeWellPostInitialConditionsPreSubGroups( WellElementSubRegion & subRegion )override;
+
+ virtual void printRates( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion ) override;
+
+ virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override;
/**@}*/
@@ -140,10 +242,9 @@ class CompositionalMultiphaseWell : public WellSolverBase
/**
* @brief Recompute the volumetric rates that are used in the well constraints
- * @param elemManager the well region manager containing the well
* @param subRegion the well subregion containing all the primary and dependent fields
*/
- void updateVolRatesForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion const & subRegion );
+ void updateVolRatesForConstraint( WellElementSubRegion const & subRegion );
/**
* @brief Recompute the current BHP pressure
@@ -159,6 +260,22 @@ class CompositionalMultiphaseWell : public WellSolverBase
*/
void updateFluidModel( WellElementSubRegion & subRegion );
+ /**
+ * @brief Update well separator using current values of pressure and composition at the reference
+ * element
+ * @param elemManager the element region manager
+
+ */
+ void updateSeparator( ElementRegionManager const & elemManager, 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,20 +289,12 @@ 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 computePerforationRates( real64 const & time_n,
- real64 const & dt, DomainPartition & domain ) override;
-
/**
* @brief Recompute all dependent quantities from primary variables (including constitutive models)
* @param subRegion the well subregion containing all the primary and dependent fields
*/
- virtual void updateState( DomainPartition & domain ) override;
+ virtual real64 updateWellState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override;
- virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override;
virtual string wellElementDofName() const override { return viewKeyStruct::dofFieldString(); }
@@ -197,61 +306,16 @@ class CompositionalMultiphaseWell : public WellSolverBase
integer useTotalMassEquation() const { return m_useTotalMassEquation; }
- /**
- * @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 assembleFluxTerms( real64 const & time_n,
- real64 const & dt,
- DomainPartition & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs )override;
- /**
- * @brief assembles the accumulation term for all the well elements
- * @param domain the physical domain object
- * @param dofManager degree-of-freedom manager associated with the linear system
- * @param matrix the system matrix
- * @param rhs the system right-hand side vector
- */
- virtual void assembleAccumulationTerms( real64 const & time_n,
- real64 const & dt,
- DomainPartition & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs ) override;
-
- /**
- * @brief assembles the 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
- * @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 assemblePressureRelations( real64 const & time_n,
- real64 const & dt,
- DomainPartition const & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs ) override;
-
/**
* @brief Sets all the negative component densities (if any) to zero.
- * @param domain the physical domain object
+ * @param subRegion the well subregion containing all the primary and dependent fields
*/
- void chopNegativeDensities( DomainPartition & domain );
+ void chopNegativeDensities( WellElementSubRegion & subRegion );
+
- struct viewKeyStruct : WellSolverBase::viewKeyStruct
+ struct viewKeyStruct : WellControls::viewKeyStruct
{
- static constexpr char const * dofFieldString() { return "compositionalWellVars"; }
+ static constexpr char const * dofFieldString() { return "wellVars"; }
// inputs
@@ -276,32 +340,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,30 +357,19 @@ class CompositionalMultiphaseWell : public WellSolverBase
virtual void initializePostInitialConditionsPreSubGroups() override;
- virtual void postRestartInitialization() override final;
- /*
- * @brief Utility function that checks the consistency of the constitutive models
- * @param[in] domain the domain partition
+ void saveState( WellElementSubRegion & subRegion );
+ virtual void postRestartInitialization( )override;
+
+ /**
+ * @brief Checks fluild model compatibility and validity
+ * @param[in] fluid the fluid to check
+ * @param[in] referenceFluid the reference fluid model
* @detail
* This function will produce an error if one of the well constitutive models
* is incompatible with the corresponding models in reservoir
* regions connected to that particular well.
*/
- void validateConstitutiveModels( DomainPartition const & domain ) const;
-
- /**
- * @brief Checks if the WellControls parameters are within the fluid tables ranges
- * @param fluid the fluid to check
- */
- 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;
-
+ void validateFluidModel( constitutive::MultiFluidBase const & fluid, constitutive::MultiFluidBase const & referenceFluid )const;
/**
* @brief Make sure that the well constraints are compatible
* @param time_n the time at the beginning of the time step
@@ -350,24 +384,15 @@ class CompositionalMultiphaseWell : public WellSolverBase
/**
* @brief Create well separator
*/
- void createSeparator();
+ virtual void createSeparator( WellElementSubRegion & subRegion ) override;
- void printRates( real64 const & time_n,
- real64 const & dt,
- DomainPartition & domain ) override;
-private:
- /**
- * @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;
-
/// flag indicating whether mass or molar formulation should be used
integer m_useMass;
@@ -395,11 +420,6 @@ class CompositionalMultiphaseWell : public WellSolverBase
/// flag indicating whether local (cell-wise) chopping of negative compositions is allowed
integer m_allowCompDensChopping;
- /// index of the target phase, used to impose the phase rate constraint
- localIndex m_targetPhaseIndex;
-
-
-
};
} // namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp
index 3ca423cd7ac..4abd716ffc4 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp
@@ -58,21 +58,7 @@ DECLARE_FIELD( globalCompDensity_n,
WRITE_AND_READ,
"Global component density at the previous converged time step" );
-DECLARE_FIELD( mixtureConnectionRate,
- "wellElementMixtureConnectionRate",
- array1d< real64 >,
- 0,
- LEVEL_0,
- WRITE_AND_READ,
- "Mixture connection rate" );
-DECLARE_FIELD( mixtureConnectionRate_n,
- "wellElementMixtureConnectionRate_n",
- array1d< real64 >,
- 0,
- NOPLOT,
- WRITE_AND_READ,
- "Mixture connection rate at the previous converged time step" );
DECLARE_FIELD( globalCompFraction,
"globalCompFraction",
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp
index 6414693bf22..939bc4f6c1e 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp
@@ -37,14 +37,13 @@
#include "physicsSolvers/fluidFlow/wells/WellFields.hpp"
#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp"
#include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp"
-#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
#include "physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp"
#include "physicsSolvers/fluidFlow/wells/kernels/ThermalSinglePhaseWellKernels.hpp"
#include "physicsSolvers/fluidFlow/wells/kernels/SinglePhasePerforationFluxKernels.hpp"
#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
{
@@ -55,7 +54,7 @@ using namespace singlePhaseWellKernels;
SinglePhaseWell::SinglePhaseWell( const string & name,
Group * const parent ):
- WellSolverBase( name, parent )
+ WellControls( name, parent )
{
m_numDofPerWellElement = 2;
m_numDofPerResElement = 1;
@@ -68,64 +67,58 @@ SinglePhaseWell::SinglePhaseWell( const string & name,
setDescription( "Flag indicating if negative pressure is allowed" );
}
-void SinglePhaseWell::registerDataOnMesh( Group & meshBodies )
+void SinglePhaseWell::registerWellDataOnMesh( WellElementSubRegion & subRegion )
{
- WellSolverBase::registerDataOnMesh( meshBodies );
-
- // loop over the wells
- forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
- {
+ WellControls::registerDataOnMesh( subRegion );
- ElementRegionManager & elemManager = mesh.getElemManager();
+ setConstitutiveNames ( subRegion );
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
- {
- subRegion.registerField< well::connectionRate_n >( getName() );
- subRegion.registerField< well::connectionRate >( getName() );
-
- PerforationData & perforationData = *subRegion.getPerforationData();
- perforationData.registerField< well::perforationRate >( getName() );
- perforationData.registerField< well::dPerforationRate >( getName() ).
- reference().resizeDimension< 1, 2 >( 2, 2 );
- if( isThermal() )
- {
- perforationData.registerField< well::energyPerforationFlux >( getName() );
- perforationData.registerField< well::dEnergyPerforationFlux >( getName() ).
- reference().resizeDimension< 1, 2 >( 2, 2 );
- }
+ if( m_referenceFluidModelName.empty() )
+ {
+ m_referenceFluidModelName = getConstitutiveName< SingleFluidBase >( subRegion );
+ }
+ subRegion.registerField< well::pressure >( getName() );
+ subRegion.registerField< well::pressure_n >( getName() );
- WellControls & wellControls = getWellControls( subRegion );
- wellControls.registerWrapper< real64 >( viewKeyStruct::currentBHPString() );
+ subRegion.registerField< well::temperature >( getName() );
+ if( isThermal() )
+ {
+ subRegion.registerField< well::temperature_n >( getName() );
+ }
+ subRegion.registerField< well::connectionRate_n >( getName() );
+ subRegion.registerField< well::connectionRate >( getName() );
+ subRegion.registerField< well::gravityCoefficient >( getName() );
+ PerforationData & perforationData = *subRegion.getPerforationData();
+ perforationData.registerField< well::gravityCoefficient >( getName() );
+
+ perforationData.registerField< well::perforationRate >( getName() );
+ perforationData.registerField< well::dPerforationRate >( getName() ).
+ reference().resizeDimension< 1, 2 >( 2, 2 );
+ if( isThermal() )
+ {
+ perforationData.registerField< well::energyPerforationFlux >( getName() );
+ perforationData.registerField< well::dEnergyPerforationFlux >( getName() ).
+ reference().resizeDimension< 1, 2 >( 2, 2 );
+ perforationData.registerField< well::gravityCoefficient >( getName() );
+ }
- wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ).
- setSizedFromParent( 0 ).
- reference().resizeDimension< 0 >( 2 + isThermal() ); // dP, dT , dQ
+ registerWrapper< real64 >( viewKeyStruct::currentBHPString() );
+ registerWrapper< real64 >( viewKeyStruct::currentVolRateString() );
- wellControls.registerWrapper< real64 >( viewKeyStruct::currentVolRateString() );
- wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentVolRateString() ).
- setSizedFromParent( 0 ).
- reference().resizeDimension< 0 >( 2 + isThermal() ); // dP, dT, dQ
+ // write rates output header
+ if( m_writeCSV > 0 && subRegion.isLocallyOwned())
+ {
+ string const fileName = GEOS_FMT( "{}/{}.csv", m_ratesOutputDir, getName() );
+ string const conditionKey = useSurfaceConditions() ? "surface" : "reservoir";
+ string const unitKey = useSurfaceConditions() ? "s" : "r";
+ // format: time,bhp,total_rate,total_vol_rate
+ makeDirsForPath( m_ratesOutputDir );
+ GEOS_LOG( GEOS_FMT( "{}: Rates CSV generated at {}", getName(), fileName ) );
+ std::ofstream outputFile( fileName );
+ outputFile << "Time [s],BHP [Pa],Total rate [kg/s],Total " << conditionKey << " volumetric rate ["< 0 && subRegion.isLocallyOwned())
- {
- string const fileName = GEOS_FMT( "{}/{}.csv", m_ratesOutputDir, wellControls.getName() );
- integer const useSurfaceConditions = wellControls.useSurfaceConditions();
- string const conditionKey = useSurfaceConditions ? "surface" : "reservoir";
- string const unitKey = useSurfaceConditions ? "s" : "r";
- // format: time,bhp,total_rate,total_vol_rate
- makeDirsForPath( m_ratesOutputDir );
- GEOS_LOG( GEOS_FMT( "{}: Rates CSV generated at {}", getName(), fileName ) );
- std::ofstream outputFile( fileName );
- outputFile << "Time [s],BHP [Pa],Total rate [kg/s],Total " << conditionKey << " volumetric rate ["<( getFlowSolverName() );
string_array const & targetRegionsNames = flowSolver.getTargetRegionNames();
auto const pos = std::find( targetRegionsNames.begin(), targetRegionsNames.end(), regionName );
GEOS_ERROR_IF( pos == targetRegionsNames.end(),
GEOS_FMT( "Region {} is not a target of the reservoir solver and cannot be used for referenceReservoirRegion in WellControl {}.",
- regionName, wellControls.getName() ),
+ regionName, getName() ),
getDataContext() );
}
}
- 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,
- "Phase rate control is not available for SinglePhaseWell",
- InputError, wellControls.getDataContext() );
- // The user always provides positive rates, but these rates are later multiplied by -1 internally for producers
- GEOS_THROW_IF( ( ( wellControls.isInjector() && targetTotalRate < 0.0 ) ||
- ( wellControls.isProducer() && targetTotalRate > 0.0) ),
- "Target total rate cannot be negative",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( !isZero( targetPhaseRate ),
- "Target phase rate cannot be used for SinglePhaseWell",
- InputError, wellControls.getDataContext() );
+}
+
+void SinglePhaseWell::initializeWellPostInitialConditionsPreSubGroups( WellElementSubRegion & subRegion )
+{
+
+ // set gravity coefficient
+ setGravCoef( subRegion, getParent().getParent().getReference< R1Tensor >( PhysicsSolverManager::viewKeyStruct::gravityVectorString() ));
+
+ // setup fluid model
+ createSeparator( subRegion );
+}
+void SinglePhaseWell::initializePostInitialConditionsPreSubGroups()
+{
+ WellControls::initializePostInitialConditionsPreSubGroups();
+}
+void SinglePhaseWell::postRestartInitialization( )
+{
+ // setup fluid separator
+ constitutive::SingleFluidBase & fluidSeparator = getSingleFluidSeparator();
+ fluidSeparator.allocateConstitutiveData( *this, 1 );
+ fluidSeparator.resize( 1 );
+
+}
+void SinglePhaseWell::createSeparator( WellElementSubRegion & subRegion )
+{
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
+ // setup fluid separator
+
+ string const fluidSeparatorName = getName() + "Separator";
+ std::unique_ptr< constitutive::ConstitutiveBase > fluidSeparatorPtr = fluid.deliverClone( fluidSeparatorName, this );
+ fluidSeparatorPtr->allocateConstitutiveData( *this, 1 );
+ fluidSeparatorPtr->resize( 1 );
+ setFluidSeparator( std::move( fluidSeparatorPtr ));
+
}
void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion )
@@ -192,7 +208,6 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion )
return;
}
-
localIndex const iwelemRef = subRegion.getTopWellElementIndex();
// subRegion data
@@ -209,47 +224,29 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion )
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 );
- string const wellControlsName = wellControls.getName();
- real64 const & refGravCoef = wellControls.getReferenceGravityCoef();
-
- real64 & currentBHP =
- wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() );
- arrayView1d< real64 > const & dCurrentBHP =
- wellControls.getReference< array1d< real64 > >( SinglePhaseWell::viewKeyStruct::dCurrentBHPString() );
-
- geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL )
+ real64 const & refGravCoef = getReferenceGravityCoef();
+ real64 & currentBHP = getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() );
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [pres,
+ dens,
+ dDens,
+ wellElemGravCoef,
+ ¤tBHP,
+ &iwelemRef,
+ &refGravCoef] ( localIndex const )
{
- integer constexpr IS_THERMAL = ISTHERMAL();
- // bring everything back to host, capture the scalars by reference
- forAll< serialPolicy >( 1, [pres,
- dens,
- dDens,
- wellElemGravCoef,
- ¤tBHP,
- &dCurrentBHP,
- &iwelemRef,
- &refGravCoef] ( localIndex const )
- {
- real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef];
- currentBHP = pres[iwelemRef] + dens[iwelemRef][0] * diffGravCoef;
- dCurrentBHP[DerivOffset::dP] = 1.0 + dDens[iwelemRef][0][DerivOffset::dP] *diffGravCoef;
- if constexpr ( IS_THERMAL )
- {
- dCurrentBHP[DerivOffset::dT] = dDens[iwelemRef][0][DerivOffset::dT] * diffGravCoef;
- }
- } );
+ real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef];
+ currentBHP = pres[iwelemRef] + dens[iwelemRef][0] * diffGravCoef;
} );
GEOS_LOG_LEVEL_BY_RANK( logInfo::WellControl,
GEOS_FMT( "{}: The BHP (at the specified reference elevation) = {} Pa",
- wellControlsName, currentBHP ) );
+ getName(), currentBHP ) );
}
-void SinglePhaseWell::updateVolRateForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion )
+void SinglePhaseWell::calculateReferenceElementRates( WellElementSubRegion & subRegion )
{
GEOS_MARK_FUNCTION;
@@ -263,83 +260,123 @@ void SinglePhaseWell::updateVolRateForConstraint( ElementRegionManager const & e
// subRegion data
- arrayView1d< real64 const > const pres =
- subRegion.getField< well::pressure >();
-
arrayView1d< real64 const > const & connRate =
subRegion.getField< well::connectionRate >();
// fluid data
+ constitutive::SingleFluidBase & fluidSeparator = getSingleFluidSeparator();
+ arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & dens = fluidSeparator.density();
+
+ real64 & currentVolRate =
+ 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 );
- arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & dens = fluid.density();
- arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > const & dDens = fluid.dDensity();
+
+ constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid )
+ {
+ typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
+ singlePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp );
+ } );
+}
+void SinglePhaseWell::updateSeparator( ElementRegionManager const & elemManager, 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();
+ string const wellControlsName = getName();
+ bool const logSurfaceCondition = isLogLevelActive< logInfo::WellControl >( getLogLevel());
+ integer const useSurfaceCond = useSurfaceConditions();
+
+ // fluid data
+ constitutive::SingleFluidBase & fluidSeparator = getSingleFluidSeparator();
+ arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & dens = fluidSeparator.density();
+
real64 flashPressure;
- if( useSurfaceConditions )
+ if( useSurfaceCond )
{
// use surface conditions
- flashPressure = wellControls.getSurfacePressure();
+ flashPressure = getSurfacePressure();
}
else
{
- if( !wellControls.referenceReservoirRegion().empty() )
+ if( !getReferenceReservoirRegion().empty() )
{
- ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion() );
+ ElementRegionBase const & region = elemManager.getRegion( getReferenceReservoirRegion() );
GEOS_ERROR_IF ( !region.hasWrapper( SinglePhaseStatistics::regionStatisticsName()),
GEOS_FMT( "WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ",
- wellControls.getName(), wellControls.referenceReservoirRegion() ),
+ getName(), getReferenceReservoirRegion() ),
getDataContext() );
- SinglePhaseStatistics::RegionStatistics const & stats = region.getReference< SinglePhaseStatistics::RegionStatistics >( SinglePhaseStatistics::regionStatisticsName() );
+ SinglePhaseStatistics::RegionStatistics const & stats = region.getReference< SinglePhaseStatistics::RegionStatistics >(
+ SinglePhaseStatistics::regionStatisticsName() );
+
GEOS_ERROR_IF( stats.averagePressure <= 0.0,
GEOS_FMT(
"No region average quantities computed. WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ",
- wellControls.getName(), wellControls.referenceReservoirRegion() ),
+ getName(), getReferenceReservoirRegion() ),
getDataContext());
- wellControls.setRegionAveragePressure( stats.averagePressure );
- wellControls.setRegionAverageTemperature( stats.averageTemperature );
+ setRegionAveragePressure( stats.averagePressure );
+ setRegionAverageTemperature( stats.averageTemperature );
}
// use region conditions
- flashPressure = wellControls.getRegionAveragePressure();
+ flashPressure = getRegionAveragePressure();
if( flashPressure < 0.0 )
{
// use segment conditions
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,
+ &useSurfaceCond,
&flashPressure,
- ¤tVolRate,
- dCurrentVolRate,
&iwelemRef,
&wellControlsName] ( localIndex const )
{
@@ -347,10 +384,10 @@ void SinglePhaseWell::updateVolRateForConstraint( ElementRegionManager const & e
// - Surface conditions: using the surface pressure provided by the user
// - Reservoir conditions: using the pressure in the top element
- if( useSurfaceConditions )
+ if( useSurfaceCond )
{
// we need to compute the surface density
- fluidWrapper.update( iwelemRef, 0, flashPressure );
+ fluidSeparatorWrapper.update( iwelemRef, 0, flashPressure );
if( logSurfaceCondition )
{
@@ -365,547 +402,519 @@ void SinglePhaseWell::updateVolRateForConstraint( ElementRegionManager const & e
}
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( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion )
{
- 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 )
+ if( getWellState())
{
- typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
- singlePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp );
- } );
-}
-real64 SinglePhaseWell::updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion )
-{
- // update volumetric rates for the well constraints
- // Warning! This must be called before updating the fluid model
- updateVolRateForConstraint( elemManager, subRegion );
+ // 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 );
+ // update density in the well elements
+ updateFluidModel( subRegion );
+ updateSeparator( elemManager, subRegion ); // Calculate fluid properties at control conditions
- // update the current BHP
- updateBHPForConstraint( subRegion );
+ // Calculate the reference element rates
+ calculateReferenceElementRates( subRegion );
+ // update the current BHP
+ updateBHPForConstraint( subRegion );
- // note: the perforation rates are updated separately
- return 0.0; // change in phasevolume fraction doesnt apply
+ }
+ return 0.0; // change in phasevolume fraction doesnt apply
}
-
-void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & time_n )
+void SinglePhaseWell::initializeWell( DomainPartition & domain, MeshLevel & mesh, WellElementSubRegion & subRegion, real64 const & time_n )
{
- GEOS_MARK_FUNCTION;
- GEOS_UNUSED_VAR( time_n );
+ GEOS_UNUSED_VAR( domain );
- // loop over the wells
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & meshLevel,
- string_array const & regionNames )
- {
- ElementRegionManager & elemManager = meshLevel.getElemManager();
+ PerforationData const & perforationData = *subRegion.getPerforationData();
+ ElementRegionManager const & elemManager = mesh.getElemManager();
+ // get the info stored on well elements
+ arrayView1d< real64 const > const wellElemGravCoef =
+ subRegion.getField< well::gravityCoefficient >();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & 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 || ( isWellOpen() && !hasNonZeroRate ) )
+ {
+ setWellState( true );
+ if( getCurrentConstraint() == nullptr )
{
- 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 )
+ if( isProducer() )
{
- // 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( elemManager, 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 );
+ forSubGroups< MinimumBHPConstraint, ProductionConstraint< VolumeRateConstraint >, ProductionConstraint< MassRateConstraint >,
+ ProductionConstraint< PhaseVolumeRateConstraint > >( [&]( auto & constraint )
+ {
+ if( ConstraintTypeId( getControl()) == constraint.getControl() )
+ {
+ setCurrentConstraint( &constraint );
+ setControl( static_cast< WellControls::Control >(constraint.getControl()) ); // tjb old
+ }
+ } );
}
+ else
+ {
+ forSubGroups< MaximumBHPConstraint, InjectionConstraint< VolumeRateConstraint >, InjectionConstraint< MassRateConstraint >,
+ InjectionConstraint< PhaseVolumeRateConstraint > >( [&]( auto & constraint )
+ {
+ if( ConstraintTypeId( getControl()) == constraint.getControl() )
+ {
+ setCurrentConstraint( &constraint );
+ setControl( static_cast< WellControls::Control >(constraint.getControl()) ); // tjb old
+ }
+ } );
+ }
+ }
- } );
-
- } );
-}
-void SinglePhaseWell::shutDownWell( real64 const time_n,
- DomainPartition const & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs )
-{
- GEOS_MARK_FUNCTION;
- GEOS_UNUSED_VAR( time_n );
-
- string const wellDofKey = dofManager.getKey( wellElementDofName() );
-
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel const & mesh,
- string_array const & regionNames )
+ PresTempInitializationKernel::SinglePhaseFlowAccessors resSinglePhaseFlowAccessors( elemManager, getFlowSolverName());
+ PresTempInitializationKernel::SingleFluidAccessors resSingleFluidAccessors( elemManager, getFlowSolverName() );
+
+ // 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(),
+ *this,
+ 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( elemManager, 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(),
+ *this,
+ 0.0, // initialization done at t = 0
+ wellElemDens,
+ connRate );
+
+ calculateReferenceElementRates( subRegion );
+ WellConstraintBase * constraint = getCurrentConstraint();
+ constraint->setBHP ( getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() ));
+ constraint->setTotalVolumeRate ( 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 )
{
-
- ElementRegionManager const & elemManager = mesh.getElemManager();
-
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion const & subRegion )
+ setWellState( false );
+ GEOS_LOG_RANK_0( "tjb shut wells "<< subRegion.getName());
+ }
+ else
+ {
+ setWellState( true );
+ // setup for restart
+ if( getCurrentConstraint() == nullptr )
{
-
- // if the well is open, we don't have to do anything, so we just return
- WellControls const & wellControls = getWellControls( subRegion );
- if( wellControls.isWellOpen( ) )
+ updateSubRegionState( elemManager, subRegion );
+ if( isProducer() )
{
- return;
+ forSubGroups< MinimumBHPConstraint, ProductionConstraint< VolumeRateConstraint >, ProductionConstraint< MassRateConstraint >,
+ ProductionConstraint< PhaseVolumeRateConstraint > >( [&](
+ auto
+ & constraint )
+ {
+ if( ConstraintTypeId( getControl()) == constraint.getControl() )
+ {
+ setCurrentConstraint( &constraint );
+ }
+ } );
}
-
- globalIndex const rankOffset = dofManager.rankOffset();
-
- arrayView1d< integer const > const ghostRank =
- subRegion.getReference< array1d< integer > >( ObjectManagerBase::viewKeyStruct::ghostRankString() );
- arrayView1d< globalIndex const > const dofNumber =
- subRegion.getReference< array1d< globalIndex > >( wellDofKey );
-
- arrayView1d< real64 const > const pres =
- subRegion.getField< fields::well::pressure >();
- arrayView1d< real64 const > const connRate =
- subRegion.getField< fields::well::connectionRate >();
-
- forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ else
{
- if( ghostRank[ei] >= 0 )
+ forSubGroups< MaximumBHPConstraint, InjectionConstraint< VolumeRateConstraint >, InjectionConstraint< MassRateConstraint >, InjectionConstraint< PhaseVolumeRateConstraint > >( [&](
+ auto
+ &
+ constraint )
{
- return;
- }
+ if( ConstraintTypeId( getControl()) == constraint.getControl() )
+ {
+ setCurrentConstraint( &constraint );
+ }
+ } );
+ }
+ }
- globalIndex const dofIndex = dofNumber[ei];
- localIndex const localRow = dofIndex - rankOffset;
- real64 rhsValue;
-
- // 4.1. Apply pressure value to the matrix/rhs
- FieldSpecificationEqual::SpecifyFieldValue( dofIndex,
- rankOffset,
- localMatrix,
- rhsValue,
- pres[ei], // freeze the current pressure value
- pres[ei] );
- localRhs[localRow] = rhsValue;
-
- // 4.2. Apply rate value to the matrix/rhs
- FieldSpecificationEqual::SpecifyFieldValue( dofIndex + 1,
- rankOffset,
- localMatrix,
- rhsValue,
- connRate[ei], // freeze the current pressure value
- connRate[ei] );
- localRhs[localRow + 1] = rhsValue;
+ }
- } );
- } );
- } );
}
-void SinglePhaseWell::assembleSystem( real64 const time,
- real64 const dt,
- DomainPartition & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs )
+real64 SinglePhaseWell::updateWellState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion )
{
- string const wellDofKey = dofManager.getKey( wellElementDofName());
+ GEOS_MARK_FUNCTION;
- // assemble the accumulation term in the mass balance equations
- assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs );
+ updateSubRegionState( elemManager, subRegion );
+ return 0.0;
+}
- // then assemble the pressure relations between well elements
- assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs );
- // then compute the perforation rates (later assembled by the coupled solver)
- computePerforationRates( time, dt, domain );
+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 );
- // then assemble the flux terms in the mass balance equations
// get a reference to the degree-of-freedom numbers
- // then assemble the flux terms in the mass balance equations
- assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs );
+ 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,
+ *this,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+ else
+ {
+ singlePhaseWellKernels::
+ FaceBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( dt,
+ dofManager.rankOffset(),
+ wellDofKey,
+ *this,
+ subRegion,
+ localMatrix,
+ localRhs );
+ }
- // then apply a special treatment to the wells that are shut
- shutDownWell( time, domain, dofManager, localMatrix, localRhs );
}
-void SinglePhaseWell::assembleFluxTerms( real64 const & time_n,
- real64 const & dt,
- DomainPartition & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs )
+
+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;
- GEOS_UNUSED_VAR( time_n );
- GEOS_UNUSED_VAR( dt );
- // loop over the wells
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel const & mesh,
- string_array const & regionNames )
- {
- ElementRegionManager const & elemManager = mesh.getElemManager();
+ // the rank that owns the reference well element is responsible for the calculations below.
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion const & subRegion )
+ if( !subRegion.isLocallyOwned() || !( getWellStatus() == WellControls::Status::OPEN ))
+ {
+ return;
+ }
+ {
+ forSubGroups< BHPConstraint, InjectionConstraint< VolumeRateConstraint >, ProductionConstraint< VolumeRateConstraint > >( [&]( auto & constraint )
{
+ if( constraint.getName() == getCurrentConstraint()->getName())
+ {
+ // found limiting constraint
- WellControls const & wellControls = getWellControls( subRegion );
- // get a reference to the degree-of-freedom numbers
- string const wellDofKey = dofManager.getKey( wellElementDofName() );
+ // fluid data
+ constitutive::SingleFluidBase & fluidSeparator = getSingleFluidSeparator();
+ integer isThermal = fluidSeparator.isThermal();
- 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 );
+ geos::internal::kernelLaunchSelectorThermalSwitch( isThermal, [&] ( auto ISTHERMAL )
+ {
+ integer constexpr IS_THERMAL = ISTHERMAL();
+
+ singlePhaseWellConstraintKernels::ConstraintHelper< IS_THERMAL >::assembleConstraintEquation( time_n,
+ *this,
+ constraint,
+ subRegion,
+ dofManager.getKey( wellElementDofName() ),
+ dofManager.rankOffset(),
+ localMatrix,
+ localRhs );
+ } );
}
} );
+ }
- } );
}
-void SinglePhaseWell::assemblePressureRelations( real64 const & time_n,
- real64 const & GEOS_UNUSED_PARAM( dt ),
- DomainPartition const & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & 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 )
{
- GEOS_MARK_FUNCTION;
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel const & mesh,
- string_array const & regionNames )
- {
+ // 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() );
- ElementRegionManager const & elemManager = mesh.getElemManager();
+ // 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();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion const & subRegion )
- {
+ geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL )
+ {
+ PressureRelationKernel::launch< ISTHERMAL >( subRegion.size(),
+ dofManager.rankOffset(),
+ wellElemDofNumber,
+ wellElemGravCoef,
+ nextWellElemIndex,
+ wellElemPressure,
+ wellElemDensity,
+ dWellElemDensity,
+ localMatrix,
+ localRhs );
+ } );
- 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() );
+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();
- geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL )
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
+ if( getWellStatus() == WellControls::Status::OPEN && !m_keepVariablesConstantDuringInitStep )
+ {
+ if( isThermal() )
+ {
+ thermalSinglePhaseWellKernels::
+ ElementBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( isProducer(),
+ dofManager.rankOffset(),
+ wellElemDofKey,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+ else
+ {
+ singlePhaseWellKernels::
+ ElementBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(),
+ wellElemDofKey,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+ // get the degrees of freedom and ghosting info
+ arrayView1d< globalIndex const > const & wellElemDofNumber =
+ subRegion.getReference< array1d< globalIndex > >( wellElemDofKey );
+ arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank();
+ arrayView1d< integer const > const elemStatus = subRegion.getLocalWellElementStatus();
+
+ arrayView1d< real64 > connRate = subRegion.getField< fields::well::connectionRate >();
+ localIndex rank_offset = dofManager.rankOffset();
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ {
+ if( wellElemGhostRank[ei] < 0 )
{
- 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 )
+ if( elemStatus[ei]==WellElementSubRegion::WellElemStatus::CLOSED )
{
- // Note: if BHP control is not viable, we switch to TOTALVOLRATE
- // if TOTALVOLRATE is not viable, we switch to BHP
+ connRate[ei] = 0.0;
+ globalIndex const dofIndex = wellElemDofNumber[ei];
+ localIndex const localRow = dofIndex - rank_offset;
- 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
+ real64 const unity = 1.0;
+ for( integer i=0; i < m_numDofPerWellElement; i++ )
{
- 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()) );
+ globalIndex const rindex = localRow+i;
+ globalIndex const cindex =dofIndex + i;
+ localMatrix.template addToRow< serialAtomic >( rindex,
+ &cindex,
+ &unity,
+ 1 );
+ localRhs[rindex] = 0.0;
}
}
- } );
-
+ }
} );
- } );
-}
-
-void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n,
- real64 const & dt,
- DomainPartition & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs )
-{
- GEOS_MARK_FUNCTION;
- GEOS_UNUSED_VAR( time_n );
- GEOS_UNUSED_VAR( dt );
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel const & mesh,
- string_array const & regionNames )
+ }
+ else
{
-
- ElementRegionManager const & elemManager = mesh.getElemManager();
-
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion const & subRegion )
+ // Zero accumulation contribution
+ arrayView1d< globalIndex const > const & wellElemDofNumber =
+ subRegion.getReference< array1d< globalIndex > >( wellElemDofKey );
+ arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank();
+
+ arrayView1d< real64 > connRate = subRegion.getField< fields::well::connectionRate >();
+ localIndex rank_offset = dofManager.rankOffset();
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
{
-
- // 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
+ if( wellElemGhostRank[ei] < 0 )
{
- singlePhaseWellKernels::
- ElementBasedAssemblyKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(),
- wellElemDofKey,
- subRegion,
- fluid,
- localMatrix,
- localRhs );
+ connRate[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;
+ }
}
} );
- } );
- // then assemble the volume balance equations
- assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs );
-}
-
-void SinglePhaseWell::assembleVolumeBalanceTerms( DomainPartition const & GEOS_UNUSED_PARAM( domain ),
- DofManager const & GEOS_UNUSED_PARAM( dofManager ),
- CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ),
- arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) )
-{
- // not implemented for single phase flow
+ // zero out current state constraint quantities
+ getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() ) = 0.0;
+ getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() )=0.0;
+ getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() )=0.0;
+ }
}
-void SinglePhaseWell::computePerforationRates( real64 const & time_n,
- real64 const & dt, DomainPartition & domain )
+void SinglePhaseWell::computeWellPerforationRates( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager const & elemManager,
+ WellElementSubRegion & subRegion )
{
GEOS_MARK_FUNCTION;
GEOS_UNUSED_VAR( time_n );
- GEOS_UNUSED_VAR( dt );
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
- {
+ // get the well data
+ PerforationData * const perforationData = subRegion.getPerforationData();
- // TODO: change the way we access the flowSolver here
- SinglePhaseBase const & flowSolver = getParent().getGroup< SinglePhaseBase >( getFlowSolverName() );
- PerforationKernel::SinglePhaseFlowAccessors resSinglePhaseFlowAccessors( mesh.getElemManager(), flowSolver.getName() );
- PerforationKernel::SingleFluidAccessors resSingleFluidAccessors( mesh.getElemManager(), flowSolver.getName() );
- ElementRegionManager & elemManager = mesh.getElemManager();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
- WellElementSubRegion & subRegion )
- {
-
- // get the well data
- PerforationData * const perforationData = subRegion.getPerforationData();
- WellControls const & wellControls = getWellControls( subRegion );
- if( wellControls.isWellOpen() && !m_keepVariablesConstantDuringInitStep )
- {
+ if( isWellOpen() && !m_keepVariablesConstantDuringInitStep )
+ {
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- SingleFluidBase const & fluid = getConstitutiveModel< SingleFluidBase >( subRegion, fluidName );
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase const & fluid = getConstitutiveModel< SingleFluidBase >( subRegion, fluidName );
- if( isThermal() )
- {
- thermalSinglePhasePerforationFluxKernels::
- PerforationFluxKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( flowSolver.getName(),
- perforationData,
- subRegion,
- fluid,
- elemManager );
- }
- else
- {
- isothermalSinglePhasePerforationFluxKernels::
- PerforationFluxKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( flowSolver.getName(),
- perforationData,
- subRegion,
- fluid,
- elemManager );
- }
- }
- else
- {
- // Zero completion flow rate
- arrayView1d< real64 > const perfRate = perforationData->getField< fields::well::perforationRate >();
- for( integer iperf=0; iperfsize(); iperf++ )
- {
- perfRate[iperf] = 0.0;
- }
- }
- } );
- } );
+ if( isThermal() )
+ {
+ thermalSinglePhasePerforationFluxKernels::
+ PerforationFluxKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( getFlowSolverName(),
+ perforationData,
+ subRegion,
+ fluid,
+ elemManager );
+ }
+ else
+ {
+ isothermalSinglePhasePerforationFluxKernels::
+ PerforationFluxKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( getFlowSolverName(),
+ perforationData,
+ subRegion,
+ fluid,
+ elemManager );
+ }
+ }
+ else
+ {
+ // Zero completion flow rate
+ arrayView1d< real64 > const perfRate = perforationData->getField< fields::well::perforationRate >();
+ for( integer iperf=0; iperfsize(); iperf++ )
+ {
+ perfRate[iperf] = 0.0;
+ }
+ }
}
real64
-SinglePhaseWell::calculateResidualNorm( real64 const & time_n,
- real64 const & dt,
- DomainPartition const & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localRhs )
+SinglePhaseWell::scalingForWellSystemSolution( WellElementSubRegion & 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;
+}
+array1d< real64 >
+SinglePhaseWell::calculateLocalWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ NonlinearSolverParameters const & nonlinearSolverParameters,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs )
{
GEOS_MARK_FUNCTION;
- integer numNorm = 1; // mass balance
+ integer numNorm = 1; // mass balance
array1d< real64 > localResidualNorm;
array1d< real64 > localResidualNormalizer;
if( isThermal() )
{
- numNorm = 2; // mass balance and energy balance
+ numNorm = 2; // mass balance and energy balance
}
localResidualNorm.resize( numNorm );
localResidualNormalizer.resize( numNorm );
@@ -914,74 +923,101 @@ SinglePhaseWell::calculateResidualNorm( real64 const & time_n,
globalIndex const rankOffset = dofManager.rankOffset();
string const wellDofKey = dofManager.getKey( wellElementDofName() );
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel const & mesh,
- string_array const & regionNames )
- {
-
- ElementRegionManager const & elemManager = mesh.getElemManager();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion const & subRegion )
- {
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
- 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() )
+ if( isWellOpen() )
+ {
+ // step 1: compute the norm in the subRegion
+ if( isThermal() )
+ {
+ real64 subRegionResidualNorm[2]{};
+ thermalSinglePhaseWellKernels::ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ *this,
+ time_n,
+ dt,
+ nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
+ // step 2: reduction across meshBodies/regions/subRegions
+
+ for( integer i=0; i >( 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] )
{
- if( subRegionResidualNorm[i] > localResidualNorm[i] )
- {
- localResidualNorm[i] = subRegionResidualNorm[i];
- }
+ localResidualNorm[i] = subRegionResidualNorm[i];
}
}
- else
+ }
+ else
+ {
+ real64 subRegionResidualNorm[1]{};
+ ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ *this,
+ time_n,
+ dt,
+ nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
+
+ // step 2: reduction across meshBodies/regions/subRegions
+
+ if( subRegionResidualNorm[0] > localResidualNorm[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];
- }
+ localResidualNorm[0] = subRegionResidualNorm[0];
}
- } );
- } );
+ }
+ }
+ return localResidualNorm;
+
+
+}
+
+real64
+SinglePhaseWell::calculateWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ NonlinearSolverParameters const & nonlinearSolverParameters,
+ 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() );
+
+ if( isWellOpen() )
+ {
+ localResidualNorm = calculateLocalWellResidualNorm( time_n,
+ dt,
+ nonlinearSolverParameters,
+ subRegion,
+ dofManager,
+ localRhs );
+ }
real64 resNorm=localResidualNorm[0];
if( isThermal() )
{
@@ -993,8 +1029,8 @@ SinglePhaseWell::calculateResidualNorm( real64 const & time_n,
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] );
+ //getConvergenceStats().setResidualValue( GEOS_FMT( "R{}", coupledSolverAttributePrefix()), globalResidualNorm[0] );
+ //getConvergenceStats().setResidualValue( "Renergy", globalResidualNorm[1] );
}
else
{
@@ -1002,16 +1038,15 @@ SinglePhaseWell::calculateResidualNorm( real64 const & time_n,
GEOS_LOG_LEVEL_RANK_0_NLR( logInfo::ResidualNorm, GEOS_FMT( " ( R{} ) = ( {:4.2e} )",
coupledSolverAttributePrefix(), resNorm ));
- getConvergenceStats().setResidualValue( GEOS_FMT( "R{}", coupledSolverAttributePrefix()), resNorm );
+ //getConvergenceStats().setResidualValue( GEOS_FMT( "R{}", coupledSolverAttributePrefix()), resNorm );
}
return resNorm;
}
-
-bool SinglePhaseWell::checkSystemSolution( DomainPartition & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution,
- real64 const scalingFactor )
+bool SinglePhaseWell::checkWellSystemSolution( WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor )
{
GEOS_MARK_FUNCTION;
@@ -1019,36 +1054,24 @@ bool SinglePhaseWell::checkSystemSolution( DomainPartition & domain,
integer numNegativePressures = 0;
real64 minPressure = 0.0;
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel const & mesh,
- string_array const & regionNames )
- {
- ElementRegionManager const & elemManager = mesh.getElemManager();
+ 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();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion const & subRegion )
+ // 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 );
- {
- 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 );
@@ -1062,14 +1085,19 @@ bool SinglePhaseWell::checkSystemSolution( DomainPartition & domain,
return (m_allowNegativePressure || numNegativePressures == 0) ? 1 : 0;
}
+
+
void
-SinglePhaseWell::applySystemSolution( DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution,
- real64 const scalingFactor,
- real64 const dt,
- DomainPartition & domain )
+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,
@@ -1096,213 +1124,256 @@ SinglePhaseWell::applySystemSolution( DofManager const & dofManager,
}
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+
+ FieldIdentifiers fieldsToBeSync;
+ if( isThermal() )
{
- FieldIdentifiers fieldsToBeSync;
- if( isThermal() )
- {
- fieldsToBeSync.addElementFields( { well::pressure::key(),
- well::connectionRate::key(),
- well::temperature::key() },
- regionNames );
- }
- else
- {
- fieldsToBeSync.addElementFields( { well::pressure::key(),
- well::connectionRate::key() },
- regionNames );
- }
- CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync,
- mesh,
- domain.getNeighbors(),
- true );
- } );
+ 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::resetStateToBeginningOfStep( DomainPartition & domain )
+
+void SinglePhaseWell::resetStateToBeginningOfStep( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion )
{
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+
+ // get a reference to the primary variables on well elements
+ arrayView1d< real64 > const & wellElemPressure =
+ subRegion.getField< well::pressure >();
+ arrayView1d< real64 const > const & wellElemPressure_n =
+ subRegion.getField< well::pressure_n >();
+ wellElemPressure.setValues< parallelDevicePolicy<> >( wellElemPressure_n );
+
+ if( isThermal() )
{
- ElementRegionManager & elemManager = mesh.getElemManager();
+ arrayView1d< real64 > const & wellElemTemperature =
+ subRegion.getField< fields::well::temperature >();
+ arrayView1d< real64 const > const & wellElemTemperature_n =
+ subRegion.getField< fields::well::temperature_n >();
+ wellElemTemperature.setValues< parallelDevicePolicy<> >( wellElemTemperature_n );
+ }
+ arrayView1d< real64 > const & connRate =
+ subRegion.getField< well::connectionRate >();
+ arrayView1d< real64 const > const & connRate_n =
+ subRegion.getField< well::connectionRate_n >();
+ connRate.setValues< parallelDevicePolicy<> >( connRate_n );
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
- {
- // get a reference to the primary variables on well elements
- arrayView1d< real64 > const & wellElemPressure =
- subRegion.getField< well::pressure >();
- arrayView1d< real64 const > const & wellElemPressure_n =
- subRegion.getField< well::pressure_n >();
- wellElemPressure.setValues< parallelDevicePolicy<> >( wellElemPressure_n );
-
- if( isThermal() )
- {
- arrayView1d< real64 > const & wellElemTemperature =
- subRegion.getField< fields::well::temperature >();
- arrayView1d< real64 const > const & wellElemTemperature_n =
- subRegion.getField< fields::well::temperature_n >();
- wellElemTemperature.setValues< parallelDevicePolicy<> >( wellElemTemperature_n );
- }
- arrayView1d< real64 > const & connRate =
- subRegion.getField< well::connectionRate >();
- arrayView1d< real64 const > const & connRate_n =
- subRegion.getField< well::connectionRate_n >();
- connRate.setValues< parallelDevicePolicy<> >( connRate_n );
+ updateSubRegionState( elemManager, subRegion );
- updateSubRegionState( elemManager, subRegion );
- } );
- } );
}
+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,
+void SinglePhaseWell::implicitStepSetup( real64 const & time_n,
real64 const & dt,
- DomainPartition & domain )
+ ElementRegionManager & elemManager,
+ WellElementSubRegion & subRegion )
{
- WellSolverBase::implicitStepSetup( time, dt, domain );
+ GEOS_MARK_FUNCTION;
+ WellControls::implicitStepSetup( time_n, dt, elemManager, 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 );
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+ 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 );
- ElementRegionManager & elemManager = mesh.getElemManager();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- 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();
- SingleFluidBase const & fluid =
- getConstitutiveModel< SingleFluidBase >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) );
- fluid.saveConvergedState();
+ validateWellConstraints( time_n, dt, subRegion );
- validateWellConstraints( time, dt, subRegion );
+ updateSubRegionState( elemManager, subRegion );
- updateSubRegionState( elemManager, subRegion );
- } );
- } );
}
void SinglePhaseWell::implicitStepComplete( real64 const & time_n,
real64 const & dt,
- DomainPartition & domain )
+ WellElementSubRegion const & subRegion )
{
- WellSolverBase::implicitStepComplete( time_n, dt, domain );
-
- if( getLogLevel() > 0 )
- {
- printRates( time_n, dt, domain );
- }
+ printRates( time_n, dt, subRegion );
}
void SinglePhaseWell::printRates( real64 const & time_n,
- real64 const & GEOS_UNUSED_PARAM( dt ),
- DomainPartition & domain )
+ real64 const & dt,
+ WellElementSubRegion const & subRegion )
{
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+
+ GEOS_UNUSED_VAR( dt ); // FIX THIS tjb
+ // the rank that owns the reference well element is responsible for the calculations below.
+ if( !subRegion.isLocallyOwned() )
{
+ return;
+ }
- ElementRegionManager & elemManager = mesh.getElemManager();
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
- {
+ // subRegion data
- // the rank that owns the reference well element is responsible for the calculations below.
- if( !subRegion.isLocallyOwned() )
- {
- return;
- }
+ arrayView1d< real64 const > const & connRate =
+ subRegion.getField< well::connectionRate >();
- localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+ // control data
- // subRegion data
- arrayView1d< real64 const > const & connRate =
- subRegion.getField< well::connectionRate >();
+ string const wellControlsName = getName();
- // control data
+ // format: time,total_rate,total_vol_rate
+ std::ofstream outputFile;
+ if( m_writeCSV > 0 )
+ {
+ outputFile.open( m_ratesOutputDir + "/" + wellControlsName + ".csv", std::ios_base::app );
+ outputFile << time_n;
+ }
- WellControls const & wellControls = getWellControls( subRegion );
- string const wellControlsName = wellControls.getName();
+ if( !isWellOpen() )
+ {
+ GEOS_LOG( GEOS_FMT( "{}: well is shut", wellControlsName ) );
+ if( outputFile.is_open())
+ {
+ // print all zeros in the rates file
+ outputFile << ",0.0,0.0,0.0" << std::endl;
+ outputFile.close();
+ }
+ return;
+ }
- // format: time,total_rate,total_vol_rate
- std::ofstream outputFile;
- if( m_writeCSV > 0 )
- {
- outputFile.open( m_ratesOutputDir + "/" + wellControlsName + ".csv", std::ios_base::app );
- outputFile << time_n;
- }
+ integer const useSurfaceCond = useSurfaceConditions();
+
+ real64 const & currentBHP =
+ getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() );
+ real64 const & currentTotalVolRate =
+ getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() );
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [&useSurfaceCond,
+ ¤tBHP,
+ connRate,
+ ¤tTotalVolRate,
+ &iwelemRef,
+ &wellControlsName,
+ &outputFile] ( localIndex const )
+ {
+ string const conditionKey = useSurfaceCond ? "surface" : "reservoir";
+ string const unitKey = useSurfaceCond ? "s" : "r";
+
+ real64 const currentTotalRate = connRate[iwelemRef];
+ GEOS_LOG( GEOS_FMT( "{}: BHP (at the specified reference elevation): {} Pa",
+ wellControlsName, currentBHP ) );
+ GEOS_LOG( GEOS_FMT( "{}: Total rate: {} kg/s; total {} volumetric rate: {} {}m3/s",
+ wellControlsName, currentTotalRate, conditionKey, currentTotalVolRate, unitKey ) );
+ if( outputFile.is_open())
+ {
+ outputFile << "," << currentBHP;
+ outputFile << "," << currentTotalRate << "," << currentTotalVolRate << std::endl;
+ outputFile.close();
+ }
+ } );
+}
- if( !wellControls.isWellOpen() )
- {
- GEOS_LOG( GEOS_FMT( "{}: well is shut", wellControlsName ) );
- if( outputFile.is_open())
- {
- // print all zeros in the rates file
- outputFile << ",0.0,0.0,0.0" << std::endl;
- outputFile.close();
- }
- return;
- }
+bool SinglePhaseWell::evaluateConstraints( real64 const & time_n,
+ WellElementSubRegion & subRegion )
+{
- integer const useSurfaceConditions = wellControls.useSurfaceConditions();
+ // create list of all constraints to process
+ std::vector< WellConstraintBase * > constraintList;
+ if( isProducer() )
+ {
+ constraintList = getProdRateConstraints();
+ // Solve minimum bhp constraint first
+ constraintList.insert( constraintList.begin(), getMinBHPConstraint() );
+ }
+ else
+ {
+ constraintList = getInjRateConstraints();
+ // Solve maximum bhp constraint first;
+ constraintList.insert( constraintList.begin(), getMaxBHPConstraint() );
+ }
+ // Get current constraint
+ WellConstraintBase * limitingConstraint = nullptr;
+ for( auto & constraint : constraintList )
+ {
+ if( constraint->getName() == getCurrentConstraint()->getName())
+ {
+ limitingConstraint = constraint;
+ // tjb. this is likely not needed. set in update state
+ constraint->setBHP ( getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() ));
+ constraint->setTotalVolumeRate ( getReference< real64 >(
+ SinglePhaseWell::viewKeyStruct::currentVolRateString() ));
+
+ GEOS_LOG_RANK_IF ( getLogLevel() > 4 && subRegion.isLocallyOwned(),
+ " Well " << subRegion.getName() << " Limiting Constraint " << limitingConstraint->getName() << " " << limitingConstraint->bottomHolePressure() << " " <<
+ limitingConstraint->totalVolumeRate() );
+ }
+ }
- real64 const & currentBHP =
- wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() );
- real64 const & currentTotalVolRate =
- wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() );
+ constraintList.erase( std::find( constraintList.begin(), constraintList.end(), limitingConstraint ) );
- // bring everything back to host, capture the scalars by reference
- forAll< serialPolicy >( 1, [&useSurfaceConditions,
- ¤tBHP,
- connRate,
- ¤tTotalVolRate,
- &iwelemRef,
- &wellControlsName,
- &outputFile] ( localIndex const )
+ // Check current against other constraints
+ for( auto & constraint : constraintList )
+ {
+
+ if( limitingConstraint->getName() != constraint->getName())
+ {
+ // limitingConstraint->getName() << std::endl;
+ if( constraint->checkViolation( *limitingConstraint, time_n ) )
{
- string const conditionKey = useSurfaceConditions ? "surface" : "reservoir";
- string const unitKey = useSurfaceConditions ? "s" : "r";
-
- real64 const currentTotalRate = connRate[iwelemRef];
- GEOS_LOG( GEOS_FMT( "{}: BHP (at the specified reference elevation): {} Pa",
- wellControlsName, currentBHP ) );
- GEOS_LOG( GEOS_FMT( "{}: Total rate: {} kg/s; total {} volumetric rate: {} {}m3/s",
- wellControlsName, currentTotalRate, conditionKey, currentTotalVolRate, unitKey ) );
- if( outputFile.is_open())
- {
- outputFile << "," << currentBHP;
- outputFile << "," << currentTotalRate << "," << currentTotalVolRate << std::endl;
- outputFile.close();
- }
- } );
- } );
- } );
+ setControl( static_cast< WellControls::Control >(constraint->getControl()) ); // tjb old
+ 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 8c07e223fb7..5f4a95c80a9 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp
@@ -20,7 +20,7 @@
#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_SINGLEPHASEWELL_HPP_
#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_SINGLEPHASEWELL_HPP_
-#include "WellSolverBase.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
#include "constitutive/fluid/singlefluid/SingleFluidLayouts.hpp"
@@ -43,7 +43,7 @@ class WellElementSubRegion;
*
* A single-phase well solver
*/
-class SinglePhaseWell : public WellSolverBase
+class SinglePhaseWell : public WellControls
{
public:
@@ -63,7 +63,7 @@ class SinglePhaseWell : public WellSolverBase
SinglePhaseWell( SinglePhaseWell const & ) = delete;
/// default move constructor
- SinglePhaseWell( SinglePhaseWell && ) = default;
+ SinglePhaseWell( SinglePhaseWell && ) = delete;
/// deleted assignment operator
SinglePhaseWell & operator=( SinglePhaseWell const & ) = delete;
@@ -76,57 +76,147 @@ class SinglePhaseWell : public WellSolverBase
*/
virtual ~SinglePhaseWell() override = default;
+ void registerWellDataOnMesh( WellElementSubRegion & subRegion ) override;
+
+ /**
+ * @defgroup WellManager Interface Functions
+ *
+ * These functions provide the primary interface that is required for derived classes
+ * The "Well" versions apply to individual well subRegions, whereas the others apply to all wells
+ */
+ /**@{*/
+ /**
+ * * @brief Initialize well for the beginning of a simulation or restart
+ * @param domain the domain
+ * @param mesh the mesh level
+ * @param subRegion the well subRegion
+ * @param time_n the current time
+ */
+ virtual void initializeWell( DomainPartition & domain, MeshLevel & mesh, WellElementSubRegion & subRegion, real64 const & time_n )override;
+
+ virtual void initializeWellPostInitialConditionsPreSubGroups( WellElementSubRegion & subRegion )override;
+ /**
+ * @brief Function to evaluate well constraints after applying the solution update
+ * @param time_n the time at the beginning of the time step
+ * @param subRegion the well subRegion
+ * @return true if all constraints are satisfied, false otherwise
+ */
+ virtual bool evaluateConstraints( real64 const & time_n,
+ WellElementSubRegion & subRegion ) override;
+ /**
+ * @copydoc WellControls::assembleWellAccumulationTerms()
+ */
+ 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 name of the node manager in the object catalog
- * @return string that contains the catalog name to generate a new NodeManager object through the object catalog.
+ * @copydoc WellControls::assembleWellConstraintTerms()
*/
- static string catalogName() { return "SinglePhaseWell"; }
+ 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;
+
/**
- * @copydoc PhysicsSolverBase::getCatalogName()
+ * @copydoc WellControls::assembleWellConstraintTerms()
*/
- string getCatalogName() const override { return catalogName(); }
+ 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 registerDataOnMesh( Group & meshBodies ) override;
+ /**
+ * @copydoc WellControls::computeWellPerforationRates()
+ */
+ virtual void computeWellPerforationRates( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager const & elemManager,
+ WellElementSubRegion & subRegion ) override;
+
+ /**
+ * @copydoc WellControls::assembleFluxTerms()
+ */
+ 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;
+ /**@}*/
/**
* @defgroup Solver Interface Functions
*
* These functions provide the primary interface that is required for derived classes
+ * The "Well" versions apply to individual well subRegions, whereas the others apply to all wells
*/
/**@{*/
+ virtual array1d< real64 >
+ calculateLocalWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ NonlinearSolverParameters const & nonlinearSolverParameters,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs )override;
+
+
virtual real64
- calculateResidualNorm( real64 const & time_n,
- real64 const & dt,
- DomainPartition const & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localRhs ) override;
+ calculateWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ NonlinearSolverParameters const & nonlinearSolverParameters,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs ) override;
+
+ virtual real64 scalingForWellSystemSolution( WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution ) override;
+ /**
+ * @copydoc WellControls::checkSystemSolution()
+ */
- virtual bool
- checkSystemSolution( DomainPartition & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution,
- real64 const scalingFactor ) override;
+ virtual bool
+ checkWellSystemSolution( WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor ) override;
+ /**
+ * @copydoc WellControls::applyWellSystemSolution()
+ */
virtual void
- applySystemSolution( DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution,
- real64 const scalingFactor,
- real64 const dt,
- DomainPartition & domain ) override;
+ applyWellSystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain,
+ MeshLevel & mesh,
+ WellElementSubRegion & subRegion ) override;
- virtual void
- resetStateToBeginningOfStep( DomainPartition & domain ) override;
- virtual void
- implicitStepSetup( real64 const & time,
- real64 const & dt,
- DomainPartition & domain ) override;
+ virtual void resetStateToBeginningOfStep( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override;
+
+ virtual void implicitStepSetup( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager & elemManager,
+ WellElementSubRegion & subRegion )override;
virtual void
implicitStepComplete( real64 const & time,
real64 const & dt,
- DomainPartition & domain ) override;
+ WellElementSubRegion const & subRegion ) override;
+
+ virtual void printRates( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion ) override;
/**@}*/
@@ -134,7 +224,7 @@ class SinglePhaseWell : public WellSolverBase
virtual string resElementDofName() const override;
- virtual localIndex numFluidComponents() const override { return 1; }
+ virtual localIndex numFluidComponents() const override { return 0; }
virtual localIndex numFluidPhases() const override { return 1; }
@@ -143,7 +233,7 @@ class SinglePhaseWell : public WellSolverBase
* @param elemManager the well region manager
* @param subRegion the well subregion containing all the primary and dependent fields
*/
- virtual void updateVolRateForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion );
+ virtual void calculateReferenceElementRates( WellElementSubRegion & subRegion );
/**
* @brief Recompute the BHP pressure that is used in the well constraints
@@ -156,110 +246,44 @@ class SinglePhaseWell : public WellSolverBase
* @param subRegion the well subRegion containing the well elements and their associated fields
*/
virtual void updateFluidModel( WellElementSubRegion & subRegion ) const;
-
/**
- * @brief Recompute the perforation rates for all the wells
- * @param domain the domain containing the mesh and fields
+ * @brief Update separator model state
+ * @param elemManager the element region manager
+ * @param subRegion the well subRegion containing the separator
*/
- virtual void computePerforationRates( real64 const & time_n,
- real64 const & dt, DomainPartition & domain ) override;
+ void updateSeparator( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion );
/**
- * @brief Recompute all dependent quantities from primary variables (including constitutive models)
- * @param elemManager the elemManager containing the well
- * @param subRegion the well subRegion containing the well elements and their associated fields
- */
- virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override;
-
- /**
- * @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,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs ) override;
+ * @brief Recompute all dependent quantities from primary variables (including constitutive
+ * models)
- /**
- * @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
+ * @param
+ * @param subRegion the well subRegion containing the well elements and their associated
*/
- virtual void assembleFluxTerms( real64 const & time_n,
- real64 const & dt,
- DomainPartition & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs ) override;
+ virtual real64 updateWellState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override;
- /**
- * @brief assembles the accumulation term for all the well elements
- * @param domain the physical domain object
- * @param dofManager degree-of-freedom manager associated with the linear system
- * @param matrix the system matrix
- * @param rhs the system right-hand side vector
- */
- virtual void assembleAccumulationTerms( real64 const & time_n,
- real64 const & dt, DomainPartition & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs ) override;
/**
- * @brief assembles the volume balance terms for all well elements
- * @param domain the physical domain object
- * @param dofManager degree-of-freedom manager associated with the linear system
- * @param matrix the system matrix
- * @param rhs the system right-hand side vector
- */
- void assembleVolumeBalanceTerms( DomainPartition const & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs );
-
- /**
- * @brief assembles the pressure relations at all connections between well elements except at the well head
- * @param time_n time at the beginning of the time step
- * @param dt the time step size
- * @param domain the physical domain object
- * @param dofManager degree-of-freedom manager associated with the linear system
- * @param matrix the system matrix
- * @param rhs the system right-hand side vector
+ * @brief Recompute all dependent quantities from primary variables (including constitutive models)
+ * @param elemManager the element region manager
+ * @param subRegion the well subRegion containing the well elements and their associated fields
*/
- virtual void assemblePressureRelations( real64 const & time_n,
- real64 const & dt,
- DomainPartition const & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs ) override;
+ virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override;
/*
* @brief apply a special treatment to the wells that are shut
- * @param time_n the time at the previous converged 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
*/
- void shutDownWell( real64 const time_n,
- DomainPartition const & domain,
+ void shutDownWell( WellElementSubRegion & subRegion,
DofManager const & dofManager,
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs );
- struct viewKeyStruct : WellSolverBase::viewKeyStruct
+ struct viewKeyStruct : WellControls::viewKeyStruct
{
- static constexpr char const * dofFieldString() { return "singlePhaseWellVars"; }
+ static constexpr char const * dofFieldString() { return "wellVars"; }
// control data (not registered on the mesh)
static constexpr char const * currentBHPString() { return "currentBHP"; }
@@ -270,10 +294,11 @@ class SinglePhaseWell : public WellSolverBase
protected:
- void printRates( real64 const & time_n,
- real64 const & dt,
- DomainPartition & domain ) override;
+ virtual void initializePostInitialConditionsPreSubGroups() override;
+
+ void saveState( WellElementSubRegion & subRegion );
+ virtual void postRestartInitialization( )override;
/// flag if negative pressure is allowed
integer m_allowNegativePressure;
@@ -281,11 +306,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
@@ -295,7 +315,15 @@ class SinglePhaseWell : public WellSolverBase
*/
virtual void validateWellConstraints( real64 const & time_n,
real64 const & dt,
- WellElementSubRegion const & subRegion ) override;
+ WellElementSubRegion const & subRegion
+ ) override;
+
+
+
+ /**
+ * @brief Create well separator
+ */
+ virtual void createSeparator( WellElementSubRegion & subRegion ) override;
};
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp
index 2cd21f32866..9e0d5472826 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp
@@ -33,21 +33,6 @@ namespace fields
namespace well
{
-DECLARE_FIELD( connectionRate,
- "connectionRate",
- array1d< real64 >,
- 0,
- LEVEL_0,
- WRITE_AND_READ,
- "Connection rate" );
-
-DECLARE_FIELD( connectionRate_n,
- "connectionRate_n",
- array1d< real64 >,
- 0,
- NOPLOT,
- WRITE_AND_READ,
- "Connection rate at the previous converged time step" );
DECLARE_FIELD( density_n,
"density_n",
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..cef4a225789
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstraintsBase.cpp
@@ -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 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" );
+
+ registerWrapper( viewKeyStruct::constraintValueString(), &m_constraintValue ).
+ setRTTypeName( rtTypes::CustomTypes::groupNameRef ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Constraint value. \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..780e19cd024
--- /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 "value"; }
+
+
+ }
+ /// 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 684306cce46..2f1805a2480 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp
@@ -22,8 +22,10 @@
#include "WellConstants.hpp"
#include "dataRepository/InputFlags.hpp"
#include "functions/FunctionManager.hpp"
-
-
+#include "mesh/PerforationFields.hpp"
+#include "fileIO/Outputs/OutputBase.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellFields.hpp"
+#include "functions/FunctionManager.hpp"
namespace geos
{
@@ -32,25 +34,25 @@ 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_numPhases( 0 ),
+ m_numComponents( 0 ),
+ m_numDofPerWellElement( 0 ),
+ m_numDofPerResElement( 0 ),
+ m_isThermal( 0 ),
+ m_keepVariablesConstantDuringInitStep( false ),
+ //m_ratesOutputDir( joinPath( OutputBase::getOutputDirectory(), "_rates" ) ),
+ m_ratesOutputDir( joinPath( OutputBase::getOutputDirectory(), parent->getName() + "_rates" ) ),
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_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_currentConstraint( nullptr ),
m_wellStatus( WellControls::Status::OPEN ),
+ m_wellOpen( false ),
+ m_statusTable( nullptr ),
m_regionAveragePressure( -1 )
{
setInputFlags( InputFlags::OPTIONAL_NONUNIQUE );
@@ -59,61 +61,26 @@ 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* " ) );
+
+
+ this->registerWrapper( viewKeyStruct::writeCSVFlagString(), &m_writeCSV ).
+ setApplyDefaultValue( 0 ).
+ setInputFlag( dataRepository::InputFlags::OPTIONAL ).
+ setDescription( "When set to 1, write the rates into a CSV file." );
+
+ this->registerWrapper( viewKeyStruct::timeStepFromTablesFlagString(), &m_timeStepFromTables ).
+ setApplyDefaultValue( 0 ).
+ setInputFlag( dataRepository::InputFlags::OPTIONAL ).
+ setDescription( "Choose time step to honor rates/bhp tables time intervals" );
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( "The target bottom-hole pressure [Pa] for the well." );
-
- 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( "Defines the global component fractions of the injected fluid." );
-
- 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 ).
@@ -155,32 +122,15 @@ 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." );
-
+#if 0
+ registerWrapper( viewKeyStruct::targetRegionsString(), &m_targetRegionNames ).
+ setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ).
+ setInputFlag( InputFlags::REQUIRED ).
+ setDescription( "Allowable regions that the solver may be applied to. Note that this does not indicate that "
+ "the solver will be applied to these regions, only that allocation will occur such that the "
+ "solver may be applied to these regions. The decision about what regions this solver will be"
+ "applied to rests in the EventManager." );
+#endif
addLogLevel< logInfo::WellControl >();
}
@@ -188,28 +138,85 @@ 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;
-}
+ //Group * baseChild = Group::createChild( childKey, childName );
+ //if( baseChild != nullptr )
+ //{
+ // return baseChild;
+ //}
+ //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 ) );
+
+ 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::switchToTotalRateControl( real64 const & val )
-{
- m_currentControl = Control::TOTALVOLRATE;
- m_targetTotalRate = 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;
-void WellControls::switchToPhaseRateControl( real64 const & val )
-{
- m_currentControl = Control::PHASEVOLRATE;
- m_targetPhaseRate = val;
+ }
+ 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
@@ -234,9 +241,17 @@ TableFunction * createWellTable( string const & tableName,
}
}
-
+void WellControls::registerWellDataOnMesh( WellElementSubRegion & subRegion )
+{
+ std::string const & regionName = subRegion.getName();
+ std::string addrWithMask( regionName );
+ std::size_t pos = addrWithMask.find( "UniqueSubRegion" );
+ std::string addr = addrWithMask.substr( 0, pos );
+ m_targetRegionNames.push_back( addr );
+}
void WellControls::postInputInitialization()
{
+ Group::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,118 +264,14 @@ void WellControls::postInputInitialization()
m_currentControl = m_inputControl;
}
- // 1.a) check target BHP
- GEOS_THROW_IF( m_targetBHP < 0,
- "Target bottom-hole pressure is negative",
- InputError, getWrapperDataContext( viewKeyStruct::targetBHPString() ) );
-
- // 1.b) check target rates
- GEOS_THROW_IF( m_targetTotalRate < 0,
- "Target rate is negative",
- InputError, getWrapperDataContext( viewKeyStruct::targetTotalRateString() ) );
-
- GEOS_THROW_IF( m_targetPhaseRate < 0,
- "Target oil rate is negative",
- InputError, getWrapperDataContext( viewKeyStruct::targetPhaseRateString() ) );
-
- GEOS_THROW_IF( m_targetMassRate < 0,
- "Target mass rate is negative",
- InputError, getWrapperDataContext( viewKeyStruct::targetMassRateString() ) );
-
- GEOS_THROW_IF( (m_injectionStream.empty() && m_injectionTemperature >= 0) ||
- (!m_injectionStream.empty() && m_injectionTemperature < 0),
- "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,
- "Invalid injection stream",
- getWrapperDataContext( viewKeyStruct::injectionStreamString() ) );
- sum += m_injectionStream[ic];
- }
- GEOS_THROW_IF( LvArray::math::abs( 1.0 - sum ) > std::numeric_limits< real64 >::epsilon(),
- "Invalid injection stream",
- InputError, getWrapperDataContext( viewKeyStruct::injectionStreamString() ) );
- }
// 3) check the flag for surface / reservoir conditions
GEOS_THROW_IF( m_useSurfaceConditions != 0 && m_useSurfaceConditions != 1,
"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())),
- "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 " << ".\n" <<
- "either " << viewKeyStruct::targetTotalRateString() <<
- " or " << viewKeyStruct::targetTotalRateTableNameString() << ".\n" <<
- "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())),
- "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())),
- "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())),
- "You have provided redundant information for well BHP." <<
- " The keywords " << viewKeyStruct::targetBHPString() << " and " << viewKeyStruct::targetBHPTableNameString() << " cannot be specified together",
- InputError, getDataContext() );
-
- GEOS_THROW_IF( ((m_targetMassRate > 0.0 && !m_targetMassRateTableName.empty())),
- "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)),
- "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())),
- "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 ));
- }
// 6.2) Check incoherent information
@@ -378,77 +289,12 @@ void WellControls::postInputInitialization()
// 8) Make sure that the initial pressure coefficient is positive
GEOS_THROW_IF( m_initialPressureCoefficient < 0,
- viewKeyStruct::initialPressureCoefficientString() <<
- "This tuning coefficient is negative",
+ 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,
- "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,
- "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,
- "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,
- "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())
{
@@ -473,37 +319,104 @@ void WellControls::postInputInitialization()
}
}
-
+void WellControls::postRestartInitialization( )
+{}
void WellControls::setWellStatus( real64 const & currentTime, WellControls::Status status )
{
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;
}
}
}
+real64 WellControls::setNextDt( real64 const & currentTime,
+ real64 const & currentDt,
+ WellElementSubRegion & subRegion )
+{
+ real64 nextDt = currentDt;
+ real64 nextDt_perf=nextDt;
+ // Find min dt from perf status tables
+ PerforationData & perforationData = *subRegion.getPerforationData();
+ string_array const & perfStatusTableName = perforationData.getPerfStatusTableName();
+ FunctionManager & functionManager = FunctionManager::getInstance();
+ // Get dt for local perforations
+ for( integer i=0; i( perfStatusTableName[i] );
+ setNextDtFromTable( tableFunction, currentTime, nextDt_perf );
+ }
+ nextDt = MpiWrapper::min< real64 >( nextDt_perf );
+ // Find min dt including rate and status tables
+ real64 const nextDt_orig = nextDt;
+ setNextDtFromTables( currentTime, nextDt );
+ //if( m_nonlinearSolverParameters.getLogLevel() > 0 && nextDt < nextDt_orig )
+ if( getLogLevel() > 0 && nextDt < nextDt_orig )
+ GEOS_LOG_RANK_0( GEOS_FMT( "{}: next time step based on tables coordinates = {}", getName(), nextDt ));
+ return nextDt;
+}
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::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 );
}
@@ -521,4 +434,189 @@ 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();
+}
+
+void WellControls::implicitStepSetup( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager & elemManager,
+ WellElementSubRegion & subRegion )
+{
+
+ GEOS_UNUSED_VAR( elemManager );
+ // Set perforation status
+ setPerforationStatus( time_n, subRegion );
+}
+void WellControls::setPerforationStatus( real64 const & time_n, WellElementSubRegion & subRegion )
+{
+ FunctionManager & functionManager = FunctionManager::getInstance();
+
+ // Set perforation status
+
+ PerforationData & perforationData = *subRegion.getPerforationData();
+ string_array const & perfStatusTableName = perforationData.getPerfStatusTableName();
+ arrayView1d< integer > perfStatus = perforationData.getLocalPerfStatus();
+ // for now set to open
+ for( integer i=0; i( perfStatusTableName[i] );
+ perfStatus[i]=PerforationData::PerforationStatus::OPEN;
+ if( tableFunction->evaluate( &time_n ) < LvArray::NumericLimits< real64 >::epsilon )
+ {
+ perfStatus[i]=PerforationData::PerforationStatus::CLOSED;
+ }
+ }
+
+ array1d< localIndex > const perfWellElemIndex = perforationData.getField< fields::perforation::wellElementIndex >();
+ // global index local elements (size == subregion.size)
+ arrayView1d< globalIndex const > globalWellElementIndex = subRegion.getGlobalWellElementIndex();
+
+ arrayView1d< integer const > const elemGhostRank = subRegion.ghostRank();
+ array1d< integer > & currentStatus = subRegion.getWellElementStatus();
+ // Local elements
+ array1d< integer > & localElemStatus = subRegion.getWellLocalElementStatus();
+
+ integer numLocalElements = subRegion.getNumLocalElements();
+ array1d< integer > segStatus( numLocalElements );
+
+ // Local perforations
+ for( integer j = 0; j < perforationData.size(); j++ )
+ {
+ localIndex const iwelem = perfWellElemIndex[j];
+ if( elemGhostRank[iwelem] < 0 )
+ {
+ if( perfStatus[j] )
+ {
+ segStatus[iwelem] +=1;
+ }
+ }
+ }
+ // Broadcast segment status so all cores have same well status
+ subRegion.setElementStatus( segStatus );
+ integer numOpenElements = 0;
+ array1d< integer > const & updatedStatus = subRegion.getWellElementStatus();
+ for( integer i=0; i0 ? setWellStatus( time_n, WellControls::Status::OPEN ) : setWellStatus( time_n, WellControls::Status::CLOSED );
+
+
+ // Set local well element status array
+ for( integer i=0; i const wellElemLocation = subRegion.getElementCenter();
+ arrayView1d< real64 > const wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >();
+
+ arrayView2d< real64 const > const perfLocation = perforationData.getField< fields::perforation::location >();
+ arrayView1d< real64 > const perfGravCoef = perforationData.getField< fields::well::gravityCoefficient >();
+
+ forAll< serialPolicy >( perforationData.size(), [=]( localIndex const iperf )
+ {
+ // precompute the depth of the perforations
+ perfGravCoef[iperf] = LvArray::tensorOps::AiBi< 3 >( perfLocation[iperf], gravVector );
+ } );
+
+ forAll< serialPolicy >( subRegion.size(), [=]( localIndex const iwelem )
+ {
+ // precompute the depth of the well elements
+ wellElemGravCoef[iwelem] = LvArray::tensorOps::AiBi< 3 >( wellElemLocation[iwelem], gravVector );
+ } );
+
+ 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
+ setReferenceGravityCoef( refElev * gravVector[2] ); // tjb remove
+}
} //namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp
index 301c3c42f7c..eea9f070f60 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp
@@ -20,12 +20,23 @@
#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONTROLS_HPP
#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONTROLS_HPP
-
+#include "physicsSolvers/PhysicsSolverBase.hpp"
#include "common/format/EnumStrings.hpp"
#include "dataRepository/Group.hpp"
#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
@@ -41,12 +52,12 @@ static constexpr auto wellControls = "WellControls";
* @class WellControls
* @brief This class describes the controls used to operate a well.
*/
-class WellControls : public dataRepository::Group
+class WellControls : public dataRepository::Group //public PhysicsSolverBase
{
public:
/** Type of wells
- * Either producer or injector.
+ * Either producer or injector
*/
enum class Type : integer
{
@@ -123,34 +134,355 @@ class WellControls : public dataRepository::Group
///@}
+
+ /// String used to form the solverName used to register single-physics solvers in CoupledSolver
+ static string coupledSolverAttributePrefix() { return "well"; }
+ /**
+ * @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;
+
+ virtual void registerWellDataOnMesh( WellElementSubRegion & subRegion ) = 0;
+ virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const = 0;
+ /**
+ * @brief Create well separator
+ */
+ virtual void createSeparator( WellElementSubRegion & subRegion ) = 0;
+
+ /**
+ * @defgroup WellManager Interface Functions
+ *
+ * These functions provide the primary interface that is required for derived classes
+ * The "Well" versions apply to individual well subRegions, whereas the others apply to all wells
+ */
+ /**@{*/
+
+ virtual void validateWellConstraints( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion ) = 0;
+ /**
+ * * @brief Initialize well for the beginning of a simulation or restart
+ * @param domain the domain
+ * @param mesh the mesh level
+ * @param subRegion the well subRegion
+ * @param time_n the current time
+ */
+ virtual void initializeWell( DomainPartition & domain, MeshLevel & mesh, WellElementSubRegion & subRegion, real64 const & time_n ) = 0;
+ /**
+ * @brief function to set the next time step size
+ * @param[in] currentTime the current time
+ * @param[in] currentDt the current time step size
+ * @param[in] domain the domain object
+ * @return the prescribed time step size
+ */
+ real64 setNextDt( real64 const & currentTime,
+ real64 const & currentDt,
+ WellElementSubRegion & subRegion );
+ // Bring the base class implicitStepSetup into scope to avoid hiding the overloaded virtual function
+
+
+ virtual void implicitStepSetup( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager & elemManager,
+ WellElementSubRegion & subRegion ) = 0;
+
+ virtual void
+ implicitStepComplete( real64 const & time,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion ) = 0;
+ virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) = 0;
+
+ /**
+ * @brief Function to evaluate well constraints after applying the solution update
+ * @param time_n the time at the beginning of the time step
+ * @param subRegion the well subRegion
+ * @return true if all constraints are satisfied, false otherwise
+ */
+ virtual bool evaluateConstraints( real64 const & time_n,
+ WellElementSubRegion & subRegion ) = 0;
+
+ /**
+ * @brief assembles the accumulation term for an individual well
+ * @param time_n time at the beginning of the time step
+ * @param dt the time step size
+ * @param subRegion the well subregion containing all the primary and dependent fields
+ * @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 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 well momentum terms for an individual well
+ * @param time_n time at the beginning of the time step
+ * @param dt the time step size
+ * @param subRegion the well subregion containing all the primary and dependent fields
+ * @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 assembleWellPressureRelations( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) = 0;
+ /**
+ * @brief assembles the well constraint terms for an individual well
+ * @param time_n time at the beginning of the time step
+ * @param dt the time step size
+ * @param subRegion the well subregion containing all the primary and dependent fields
+ * @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 assembleWellConstraintTerms( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) = 0;
+
+ /**
+ * @brief Recompute the perforation rates for all the wells
+ * @param time_n the time at the beginning of the time step
+ * @param dt the time step size
+ * @param elemManager the element region manager
+ * @param subRegion the well subregion containing all the primary and dependent fields
+ */
+ virtual void computeWellPerforationRates( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager const & elemManager,
+ WellElementSubRegion & subRegion ) = 0;
+
+ /**
+ * @brief assembles the flux terms for individual well for all connections between well elements
+ * @param time_n previous time value
+ * @param dt time step
+ * @param subRegion the well subregion containing all the primary and dependent fields
+ * @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 ) = 0;
+ virtual real64
+ calculateWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ NonlinearSolverParameters const & nonlinearSolverParameters,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs ) = 0;
+
+ virtual array1d< real64 >
+ calculateLocalWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ NonlinearSolverParameters const & nonlinearSolverParameters,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs ) = 0;
+
+ virtual real64
+ scalingForWellSystemSolution( WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution ) = 0;
+
+ virtual bool
+ checkWellSystemSolution( WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor ) = 0;
+
+ virtual void
+ applyWellSystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain,
+ MeshLevel & mesh,
+ WellElementSubRegion & subRegion ) = 0;
+
+ /**
+ * @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( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) = 0;
+
+ /**
+ * @brief Reset the well state to the beginning of the time step
+ * @param subRegion the well subregion containing all the primary and dependent fields
+ */
+ virtual void resetStateToBeginningOfStep( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) = 0;
+
+ virtual void postInputInitialization() override;
+
+ virtual void initializeWellPostInitialConditionsPreSubGroups( WellElementSubRegion & subRegion ) = 0;
+ virtual void printRates( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion ) = 0;
+ /**@}*/
+ /**
+ * @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.
+ */
+ 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;
+ }
+
+
+ /**
+ * @copydoc forInjectionConstraints(LAMBDA &&)
+ */
+ 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 );
+ } );
+ }
+ }
+ /**
+ * @copydoc forProductionConstraints(LAMBDA &&)
+ */
+ 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 );
+ } );
+ }
+ }
/**
* @name Getters / Setters
*/
///@{
/**
- * @brief Set the control type to BHP and set a numerical value for the control.
- * @param[in] val value for the BHP control
+ * @brief Get the Constitutive Name object
+ *
+ * @tparam CONSTITUTIVE_BASE_TYPE the base type of the constitutive model.
+ * @param subRegion the element subregion on which the constitutive model is registered
+ * @return the name name of the constitutive model of type CONSTITUTIVE_BASE_TYPE registered on the subregion.
*/
- void switchToBHPControl( real64 const & val );
+ template< typename CONSTITUTIVE_BASE_TYPE >
+ static string getConstitutiveName( ElementSubRegionBase const & subRegion );
/**
- * @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
+ * @brief Register wrapper with given name and store constitutive model name on the subregion
+ *
+ * @tparam CONSTITUTIVE the base type of the constitutive model.
+ * @param subRegion the subregion on which the constitutive model is registered.
+ * @param wrapperName the wrapper name to register.
+ * @param constitutiveType the type description of the constitutive model.
*/
- void switchToTotalRateControl( real64 const & val );
+ template< typename CONSTITUTIVE >
+ void setConstitutiveName( ElementSubRegionBase & subRegion, string const & wrapperName, string const & constitutiveType ) const;
/**
- * @brief Set the control type to mass rate and set a numerical value for the control.
- * @param[in] val value for the mass rate
+ * @brief return the list of target regions
+ * @return the array of region names
*/
- void switchToMassRateControl( real64 const & val );
+ string_array const & getTargetRegionNames() const {return m_targetRegionNames;}
+ /**
+ * @brief Get the control type for the well.
+ * @return the Control enum enforced at the well
+ */
+ std::string getFlowSolverName() const { return m_flowSolverName; }
/**
- * @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
+ * @brief Set the control type for the well.
+ * @param[in] flowSolverName the name of the flow solver
*/
- void switchToPhaseRateControl( real64 const & val );
+ void setFlowSolverName( const std::string & flowSolverName ) { m_flowSolverName = flowSolverName; }
/**
* @brief Get the control type for the well.
@@ -170,12 +502,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
* @return the reference gravity coefficient
@@ -187,60 +513,38 @@ class WellControls : public dataRepository::Group
*/
void setReferenceGravityCoef( real64 const & refGravCoef ) { m_refGravCoef = refGravCoef; }
-
/**
- * @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
+ * @brief Const accessor for the phase constraint index
+ * @return phase index associated with phase constraint
*/
- const string & getTargetPhaseName() const { return m_targetPhaseName; }
+ integer getConstraintPhaseIndex() const;
/**
- * @brief Const accessor for the composition of the injection stream
- * @return a global component fraction vector
+ * @brief Return the reference elvation where pressure constraint is measured
+ * @return vertical location of constraint
*/
- arrayView1d< real64 const > getInjectionStream() const { return m_injectionStream; }
+ real64 getReferenceElevation() const;
- /**
- * @brief Const accessor for the temperature of the injection stream
- * @return the temperature of the injection stream
- */
- real64 getInjectionTemperature() const { return m_injectionTemperature; }
/**
* @brief Getter for the flag specifying whether we check rates at surface or reservoir conditions
@@ -252,7 +556,7 @@ class WellControls : public dataRepository::Group
* @brief Getter for the reservoir region associated with reservoir volume constraint
* @return name of reservoir region
*/
- string referenceReservoirRegion() const { return m_referenceReservoirRegion; }
+ string getReferenceReservoirRegion() const { return m_referenceReservoirRegion; }
/**
* @brief Getter for the surface pressure when m_useSurfaceConditions == 1
@@ -278,12 +582,48 @@ class WellControls : public dataRepository::Group
*/
bool isProducer() const { return ( m_type == Type::PRODUCER ); }
+ /**
+ * @brief getter for iso/thermal switch
+ * @return True if thermal
+ */
+ integer isThermal() const { return m_isThermal; }
+
+ /**
+ * @brief setter for iso/thermal switch
+ * @param[in] isThermal
+ */
+
+ void setThermal( bool isThermal ) { m_isThermal=isThermal; }
/**
* @brief Is the well open (or shut) at currentTime, status initalized in WellSolverBase::implicitStepSetup
* @return a boolean
*/
bool isWellOpen() const;
+ /**
+ * @brief Set the well state
+ * @param[in] open boolean
+ */
+ void setWellState( bool open );
+ /**
+ * @brief Get the well state
+ * @return a boolean
+ */
+ bool getWellState() const;
+
+ /**
+ * @brief Set the current consrtaint
+ * @param[in] currentConstraint pointer to constraint
+ */
+ void setCurrentConstraint( WellConstraintBase * currentConstraint ) { m_currentConstraint = currentConstraint;}
+ /**
+ * @brief Get the current consrtaint
+ * @return pointer to constraint
+ */
+ 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
@@ -302,6 +642,17 @@ class WellControls : public dataRepository::Group
* @param[inout] nextDt the time step
*/
void setNextDtFromTables( real64 const & currentTime, real64 & nextDt );
+ /**
+ * @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; }
+
/**
* @brief setter for multi fluid separator
@@ -314,6 +665,12 @@ 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,34 +709,36 @@ class WellControls : public dataRepository::Group
WellControls::Status getWellStatus () const { return m_wellStatus; }
///@}
+
+ virtual string wellElementDofName() const = 0;
+
+ virtual string resElementDofName() const = 0;
+
+ virtual localIndex numFluidComponents() const = 0;
+
+ virtual localIndex numFluidPhases() const = 0;
/**
* @brief Struct to serve as a container for variable strings and keys.
* @struct viewKeyStruct
*/
struct viewKeyStruct
{
+ /// String key for the fluid model names
+ static constexpr char const * fluidNamesString() { return "fluidNames"; }
+ /// String key for the write CSV flag
+ static constexpr char const * writeCSVFlagString() { return "writeCSV"; }
+ static constexpr char const * timeStepFromTablesFlagString() { return "timeStepFromTables"; }
+/// @return string for the targetRegions wrapper
+ static constexpr char const * targetRegionsString() { return "targetRegions"; }
+
/// String key for the well reference elevation (for BHP control)
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 +747,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,24 +756,102 @@ 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;
+ void setPerforationStatus( real64 const & time_n, WellElementSubRegion & subRegion );
+ void setGravCoef( WellElementSubRegion & subRegion, R1Tensor const & gravVector );
+ /**
+ * @brief Set next time step based on a table function
+ * @param[in] table the table function
+ * @param[in] currentTime the current time
+ * @param[inout] nextDt the time step
+ */
static void setNextDtFromTable( TableFunction const * table, real64 const currentTime, real64 & nextDt );
-protected:
+ /**
+ * @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 );
- virtual void postInputInitialization() override;
+ /**
+ * @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; };
+
+ /**
+ * @brief Getters for constraint lists
+ */
+ 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 postRestartInitialization( )override;
private:
+ /// List of names of regions the solver will be applied to
+ string_array m_targetRegionNames;
+
+protected:
/// Well type (as Type enum)
Type m_type;
+ /// Name of the flow solver managing this well
+ std::string m_flowSolverName;
+
+ /// the max number of fluid phases
+ integer m_numPhases;
+
+ /// the number of fluid components
+ integer m_numComponents;
+
+ /// the number of Degrees of Freedom per well element
+ integer m_numDofPerWellElement;
+
+ /// the number of Degrees of Freedom per reservoir element
+ integer m_numDofPerResElement;
+
+ /// flag indicating whether thermal formulation is used
+ integer m_isThermal;
+ /// flag to freeze the initial state during initialization in coupled problems
+ bool m_keepVariablesConstantDuringInitStep;
+ /// rates output
+ integer m_writeCSV;
+ string const m_ratesOutputDir;
+
+ // flag to enable time step selection base on rates/bhp tables coordinates
+ integer m_timeStepFromTables;
/// Reference elevation
real64 m_refElevation;
@@ -434,33 +864,15 @@ 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;
// Fuild model to compute properties for constraint equation user specified conditions
std::unique_ptr< constitutive::ConstitutiveBase > m_fluidSeparatorPtr;
+ /// name of the fluid constitutive model used as a reference for component/phase description on subregion
+ string m_referenceFluidModelName;
+
/// Reservoir region associated with reservoir volume constraint
string m_referenceReservoirRegion;
@@ -470,21 +882,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;
-
/// Perforation status table name
string m_perfStatusTableName;
@@ -494,28 +891,29 @@ class WellControls : public dataRepository::Group
/// Tuning coefficient for the initial well pressure
real64 m_initialPressureCoefficient;
- /// Rate sign. +1 for injector, -1 for producer
- real64 m_rateSign;
+ // Current constrint
+ WellConstraintBase * m_currentConstraint;
- /// Total rate table
- TableFunction const * m_targetTotalRateTable;
+ // Minimum and maximum BHP and WHP constraints
+ MinimumBHPConstraint * m_minBHPConstraint;
+ MaximumBHPConstraint * m_maxBHPConstraint;
- /// Phase rate table
- TableFunction const * m_targetPhaseRateTable;
+ // Lists of rate constraints
+ std::vector< WellConstraintBase * > m_productionRateConstraintList;
+ std::vector< WellConstraintBase * > m_injectionRateConstraintList;
- /// Mass rate table
- TableFunction const * m_targetMassRateTable;
+ /// Well status
+ WellControls::Status m_wellStatus;
+
+ /// Well open flag
+ bool m_wellOpen;
- /// BHP table
- TableFunction const * m_targetBHPTable;
+ /// Well status table name
+ string m_statusTableName;
/// Status table
TableFunction const * m_statusTable;
- /// Well status
- WellControls::Status m_wellStatus;
-
-
/// Region average pressure used in volume rate constraint calculations
real64 m_regionAveragePressure;
@@ -524,11 +922,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",
@@ -536,6 +938,62 @@ ENUM_STRINGS( WellControls::Control,
"uninitialized" );
+template< typename CONSTITUTIVE >
+void WellControls::setConstitutiveName( ElementSubRegionBase & subRegion, string const & wrapperName, string const & constitutiveType ) const
+{
+ subRegion.registerWrapper< string >( wrapperName ).
+ setPlotLevel( dataRepository::PlotLevel::NOPLOT ).
+ setRestartFlags( dataRepository::RestartFlags::NO_WRITE ).
+ setSizedFromParent( 0 );
+
+ string & constitutiveName = subRegion.getReference< string >( wrapperName );
+ constitutiveName = getConstitutiveName< CONSTITUTIVE >( subRegion );
+ GEOS_ERROR_IF( constitutiveName.empty(), GEOS_FMT( "{}: {} constitutive model not found on subregion {}",
+ getDataContext(), constitutiveType, subRegion.getName() ) );
+}
+template< typename CONSTITUTIVE_BASE_TYPE >
+string WellControls::getConstitutiveName( ElementSubRegionBase const & subRegion )
+{
+ string validName;
+ dataRepository::Group const & constitutiveModels = subRegion.getConstitutiveModels();
+
+ constitutiveModels.forSubGroups< CONSTITUTIVE_BASE_TYPE >( [&]( dataRepository::Group const & model )
+ {
+ GEOS_ERROR_IF( !validName.empty(), "A valid constitutive model was already found." );
+ validName = model.getName();
+ } );
+
+ return validName;
+}
+
+/**
+ * @brief Get the Constitutive Model object
+ * @tparam BASETYPE the base type of the constitutive model.
+ * @tparam LOOKUP_TYPE the type of the key used to look up the constitutive model.
+ * @param dataGroup the data group containing the constitutive models.
+ * @param key the key used to look up the constitutive model.
+ * @return the constitutive model of type @p BASETYPE registered on the @p dataGroup with the key @p key.
+ */
+template< typename BASETYPE = constitutive::ConstitutiveBase, typename LOOKUP_TYPE >
+static BASETYPE const & getConstitutiveModel( dataRepository::Group const & dataGroup, LOOKUP_TYPE const & key )
+{
+ dataRepository::Group const & constitutiveModels = dataGroup.getGroup( ElementSubRegionBase::groupKeyStruct::constitutiveModelsString() );
+ return constitutiveModels.getGroup< BASETYPE >( key );
+}
+/**
+ * @brief Get the Constitutive Model object
+ * @tparam BASETYPE the base type of the constitutive model.
+ * @tparam LOOKUP_TYPE the type of the key used to look up the constitutive model.
+ * @param dataGroup the data group containing the constitutive models.
+ * @param key the key used to look up the constitutive model.
+ * @return the constitutive model of type @p BASETYPE registered on the @p dataGroup with the key @p key.
+ */
+template< typename BASETYPE = constitutive::ConstitutiveBase, typename LOOKUP_TYPE >
+static BASETYPE & getConstitutiveModel( dataRepository::Group & dataGroup, LOOKUP_TYPE const & key )
+{
+ dataRepository::Group & constitutiveModels = dataGroup.getGroup( ElementSubRegionBase::groupKeyStruct::constitutiveModelsString() );
+ return constitutiveModels.getGroup< BASETYPE >( key );
+}
} //namespace geos
#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONTROLS_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp
index 5f77922f4ee..3bb07399534 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp
@@ -34,6 +34,21 @@ namespace fields
namespace well
{
+DECLARE_FIELD( connectionRate,
+ "wellElementConnectionRate",
+ array1d< real64 >,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Connection rate" );
+
+DECLARE_FIELD( connectionRate_n,
+ "wellElementConnectionRate_n",
+ array1d< real64 >,
+ 0,
+ NOPLOT,
+ WRITE_AND_READ,
+ "Connection rate at the previous converged time step" );
DECLARE_FIELD( energyPerforationFlux,
"energyPerforationFlux",
array1d< real64 >,
@@ -50,6 +65,61 @@ DECLARE_FIELD( dEnergyPerforationFlux,
NO_WRITE,
"Derivative of energy perforation flux with respect to pressure temperature and global component density (compositional only)" );
+DECLARE_FIELD( pressure,
+ "pressure",
+ array1d< real64 >,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Pressure" );
+
+DECLARE_FIELD( pressure_n,
+ "pressure_n",
+ array1d< real64 >,
+ 0,
+ NOPLOT,
+ WRITE_AND_READ,
+ "Pressure at the previous converged time step" );
+
+DECLARE_FIELD( temperature,
+ "temperature",
+ array1d< real64 >,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Temperature" );
+
+DECLARE_FIELD( temperature_n,
+ "temperature_n",
+ array1d< real64 >,
+ 0,
+ NOPLOT,
+ WRITE_AND_READ,
+ "Temperature at the previous converged time step" );
+
+DECLARE_FIELD( gravityCoefficient,
+ "gravityCoefficient",
+ array1d< real64 >,
+ 0,
+ NOPLOT,
+ WRITE_AND_READ,
+ "Gravity coefficient (dot product of gravity acceleration by gravity vector)" );
+
+DECLARE_FIELD( pressureScalingFactor,
+ "pressureScalingFactor",
+ array1d< real64 >,
+ 1,
+ NOPLOT,
+ NO_WRITE,
+ "Scaling factors for pressure" );
+
+DECLARE_FIELD( temperatureScalingFactor,
+ "temperatureScalingFactor",
+ array1d< real64 >,
+ 1,
+ NOPLOT,
+ NO_WRITE,
+ "Scaling factors for temperature" );
}
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..3c84f70f1a7
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.cpp
@@ -0,0 +1,76 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 );
+ return ( LvArray::math::abs( currentValue ) <= LvArray::math::abs( 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/WellManager.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellManager.cpp
new file mode 100644
index 00000000000..ee182b5d096
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellManager.cpp
@@ -0,0 +1,1076 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 WellManager.cpp
+ */
+
+#include "WellManager.hpp"
+
+#include "mesh/DomainPartition.hpp"
+#include "mesh/PerforationFields.hpp"
+#include "mesh/WellElementRegion.hpp"
+#include "mesh/WellElementSubRegion.hpp"
+#include "physicsSolvers/LogLevelsInfo.hpp"
+#include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp"
+#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp"
+#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp"
+#include "physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
+
+#include "physicsSolvers/fluidFlow/wells/WellFields.hpp"
+#include "fileIO/Outputs/OutputBase.hpp"
+#include "functions/FunctionManager.hpp"
+namespace geos
+{
+
+using namespace dataRepository;
+using namespace fields;
+
+WellManager::WellManager( string const & name,
+ Group * const parent )
+ : PhysicsSolverBase( name, parent ),
+ m_useMass( false ),
+ m_useTotalMassEquation( 1 ),
+ m_isThermal( 0 ),
+ m_isCompositional( true ),
+ m_minScalingFactor( 0.01 ),
+ m_allowCompDensChopping( 1 )
+{
+ this->getWrapper< string >( viewKeyStruct::discretizationString() ).
+ setInputFlag( InputFlags::FALSE );
+
+ registerWrapper( viewKeyStruct::isThermalString(), &m_isThermal ).
+ setApplyDefaultValue( 0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Flag indicating whether the problem is thermal or not." );
+
+
+ this->registerWrapper( viewKeyStruct::useMassFlagString(), &m_useMass ).
+ setApplyDefaultValue( 0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Use mass formulation instead of molar" );
+
+ this->registerWrapper( viewKeyStruct::useTotalMassEquationString(), &m_useTotalMassEquation ).
+ setApplyDefaultValue( 1 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Use total mass equation" );
+
+ this->registerWrapper( viewKeyStruct::allowLocalCompDensChoppingString(), &m_allowCompDensChopping ).
+ setSizedFromParent( 0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setApplyDefaultValue( 1 ).
+ setDescription( "Flag indicating whether local (cell-wise) chopping of negative compositions is allowed" );
+
+ this->registerWrapper( viewKeyStruct::timeStepFromTablesFlagString(), &m_timeStepFromTables ).
+ setApplyDefaultValue( 0 ).
+ setInputFlag( dataRepository::InputFlags::OPTIONAL ).
+ setDescription ( "Choose time step to honor rates/bhp tables time intervals" );
+
+}
+Group * WellManager::createChild( string const & childKey, string const & childName )
+{
+ static std::set< string > const childTypes = {
+ keys::compositionalMultiphaseWell,
+ keys::singlePhaseWell,
+ PhysicsSolverBase::groupKeyStruct::linearSolverParametersString(),
+ PhysicsSolverBase::groupKeyStruct::nonlinearSolverParametersString(),
+ };
+ GEOS_ERROR_IF( childTypes.count( childKey ) == 0,
+ CatalogInterface::unknownTypeError( childKey, getDataContext(), childTypes ),
+ getDataContext() );
+ if( childKey == keys::compositionalMultiphaseWell )
+ {
+ setCompositional( true );
+ return ®isterGroup< CompositionalMultiphaseWell >( childName );
+ }
+ else if( childKey == keys::singlePhaseWell )
+ {
+ setCompositional( false );
+ return ®isterGroup< SinglePhaseWell >( childName );
+ }
+ else
+ {
+ PhysicsSolverBase::createChild( childKey, childName );
+ return nullptr;
+ }
+}
+
+void WellManager::expandObjectCatalogs()
+{
+ createChild( keys::compositionalMultiphaseWell, keys::compositionalMultiphaseWell );
+ createChild( keys::singlePhaseWell, keys::singlePhaseWell );
+}
+
+void WellManager::registerDataOnMesh( Group & meshBodies )
+{
+
+ //std::string const & flowSolverName = getParent().getName();//getGroup< CompositionalMultiphaseBase >().getName();
+ // CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
+
+ forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+
+ ElementRegionManager & elemManager = mesh.getElemManager();
+
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+
+ WellControls & well = getWellControls( subRegion );
+ //well.setFlowSolverName( flowSolver.getName() );
+ well.setThermal( isThermal() );
+ well.registerWellDataOnMesh( subRegion );
+ m_numFluidPhases = well.numFluidPhases();
+ m_numFluidComponents = well.numFluidComponents();
+
+
+ } );
+ } );
+ // 1. Set key dimensions of the problem
+ // Empty check needed to avoid errors when running in schema generation mode.
+
+ // 1 pressure + NC compositions + 1 connectionRate + temp if thermal
+ m_numDofPerWellElement = isThermal() ? m_numFluidComponents + 3 : m_numFluidComponents + 2;
+ // 1 pressure + NC compositions + temp if thermal
+ m_numDofPerResElement = isThermal() ? m_numFluidComponents + 2 : m_numFluidComponents + 1;
+ #if 0
+ DomainPartition const & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" );
+ ConstitutiveManager const & cm = domain.getConstitutiveManager();
+
+ forDiscretizationOnMeshTargets( meshBodies, [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+ if( m_referenceFluidModelName.empty() )
+ {
+ m_referenceFluidModelName = getConstitutiveName< MultiFluidBase >( subRegion );
+ }
+ } );
+ } );
+
+ // 1. Set key dimensions of the problem
+ // Empty check needed to avoid errors when running in schema generation mode.
+ if( !m_referenceFluidModelName.empty() )
+ {
+ MultiFluidBase const & fluid0 = cm.getConstitutiveRelation< MultiFluidBase >( m_referenceFluidModelName );
+ m_numPhases = fluid0.numFluidPhases();
+ m_numComponents = fluid0.numFluidComponents();
+ }
+ // 1 pressure + NC compositions + 1 connectionRate + temp if thermal
+ m_numDofPerWellElement = isThermal() ? m_numComponents + 3 : m_numComponents + 2;
+ // 1 pressure + NC compositions + temp if thermal
+ m_numDofPerResElement = isThermal() ? m_numComponents + 2 : m_numComponents + 1;
+
+ // loop over the wells
+ forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+
+ ElementRegionManager & elemManager = mesh.getElemManager();
+
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+ string const & fluidName = getConstitutiveName< MultiFluidBase >( subRegion );
+ MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
+
+ // The resizing of the arrays needs to happen here, before the call to initializePreSubGroups,
+ // to make sure that the dimensions are properly set before the timeHistoryOutput starts its initialization.
+
+ subRegion.registerField< well::globalCompDensity >( getName() ).
+ reference().resizeDimension< 1 >( m_numComponents );
+ subRegion.registerField< well::globalCompDensity_n >( getName() ).
+ reference().resizeDimension< 1 >( m_numComponents );
+
+ subRegion.registerField< well::connectionRate >( getName() );
+ subRegion.registerField< well::connectionRate_n >( getName() );
+
+ subRegion.registerField< well::globalCompFraction >( getName() ).
+ setDimLabels( 1, fluid.componentNames() ).
+ reference().resizeDimension< 1 >( m_numComponents );
+ subRegion.registerField< well::dGlobalCompFraction_dGlobalCompDensity >( getName() ).
+ reference().resizeDimension< 1, 2 >( m_numComponents, m_numComponents );
+
+ subRegion.registerField< well::phaseVolumeFraction >( getName() ).
+ setDimLabels( 1, fluid.phaseNames() ).
+ reference().resizeDimension< 1 >( m_numPhases );
+ subRegion.registerField< well::dPhaseVolumeFraction >( getName() ).
+ reference().resizeDimension< 1, 2 >( m_numPhases, m_numComponents + 2 ); // dP, dT, dC
+
+ subRegion.registerField< well::totalMassDensity >( getName() );
+ subRegion.registerField< well::dTotalMassDensity >( getName() ).
+ reference().resizeDimension< 1 >( m_numComponents +2 ); // dP, dT, dC
+
+ subRegion.registerField< well::phaseVolumeFraction_n >( getName() ).
+ reference().resizeDimension< 1 >( m_numPhases );
+
+ subRegion.registerField< well::pressureScalingFactor >( getName() );
+ subRegion.registerField< well::temperatureScalingFactor >( getName() );
+ subRegion.registerField< well::globalCompDensityScalingFactor >( getName() );
+
+ PerforationData & perforationData = *subRegion.getPerforationData();
+ perforationData.registerField< well::compPerforationRate >( getName() ).
+ reference().resizeDimension< 1 >( m_numComponents );
+
+ perforationData.registerField< well::dCompPerforationRate >( getName() ).
+ reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 );
+ if( fluid.isThermal() )
+ {
+ perforationData.registerField< well::energyPerforationFlux >( getName() );
+ perforationData.registerField< well::dEnergyPerforationFlux >( getName() ).
+ reference().resizeDimension< 1, 2 >( 2, m_numComponents+2 );
+ }
+
+ 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() );
+
+ wellControls.registerWrapper< real64 >( viewKeyStruct::currentMassRateString() );
+
+ // write rates output header
+ // the rank that owns the reference well element is responsible
+ if( m_writeCSV > 0 && subRegion.isLocallyOwned() )
+ {
+ string const fileName = GEOS_FMT( "{}/{}.csv", m_ratesOutputDir, wellControls.getName() );
+ string const massUnit = m_useMass ? "kg" : "mol";
+ integer const useSurfaceConditions = wellControls.useSurfaceConditions();
+ string const conditionKey = useSurfaceConditions ? "surface" : "reservoir";
+ string const unitKey = useSurfaceConditions ? "s" : "r";
+ integer const numPhase = m_numPhases;
+ integer const numComp = m_numComponents;
+ // format: time,bhp,total_rate,total_vol_rate,phase0_vol_rate,phase1_vol_rate,...
+ makeDirsForPath( m_ratesOutputDir );
+ GEOS_LOG( GEOS_FMT( "{}: Rates CSV generated at {}", getName(), fileName ) );
+ std::ofstream outputFile( fileName );
+ outputFile << "Time [s],dt[s],BHP [Pa],Total rate [" << massUnit << "/s],Total " << conditionKey << " volumetric rate [" << unitKey << "m3/s]";
+ for( integer ip = 0; ip < numPhase; ++ip )
+ {
+ outputFile << ",Phase" << ip << " " << conditionKey << " volumetric rate [" << unitKey << "m3/s]";
+ }
+ for( integer ic = 0; ic < numComp; ++ic )
+ {
+ outputFile << ",Component" << ic << " rate [" << massUnit << "/s]";
+ }
+ outputFile << std::endl;
+ outputFile.close();
+ }
+ } );
+ } );
+#endif
+}
+
+WellControls & WellManager::getWell( WellElementSubRegion const & subRegion )
+{
+ return this->getGroup< WellControls >( subRegion.getWellControlsName());
+}
+
+void WellManager::implicitStepSetup( real64 const & time_n,
+ real64 const & dt,
+ DomainPartition & domain )
+{
+
+ forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+
+ ElementRegionManager & elemManager = mesh.getElemManager();
+
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+
+ WellControls & well = getWell( subRegion );
+ //well.implicitStepSetup( time_n, dt, domain );
+ well.implicitStepSetup( time_n, dt, elemManager, subRegion );
+ } )
+ ;
+ } );
+}
+real64
+WellManager::setNextDt( real64 const & currentTime, const real64 & currentDt, geos::DomainPartition & domain )
+{
+
+ real64 nextDt = PhysicsSolverBase::setNextDt( currentTime, currentDt, domain );
+
+ if( m_timeStepFromTables )
+ {
+ real64 nextDt_orig = nextDt;
+ real64 nextDtLocal = nextDt;
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+
+ WellControls & wellControls = getWellControls( subRegion );
+ real64 nextDtWell = wellControls.setNextDt( currentTime, nextDt, subRegion );
+ if( nextDtWell < nextDtLocal )
+ {
+ nextDtLocal = nextDtWell;
+ }
+ } );
+ } );
+ // get the minimum across all ranks
+ nextDt = MpiWrapper::min< real64 >( nextDtLocal );
+ if( getLogLevel() > 0 && nextDt < nextDt_orig )
+ GEOS_LOG_RANK_0( GEOS_FMT( "{}: next time step based on tables coordinates = {}", getName(), nextDt ));
+ }
+
+ return nextDt;
+}
+localIndex WellManager::numDofPerWellElement() const
+{
+ return m_numDofPerWellElement;
+}
+
+localIndex WellManager::numDofPerResElement() const
+{
+ return m_numDofPerResElement;
+}
+integer WellManager::isThermal() const
+{
+ return m_isThermal;
+}
+
+string WellManager::wellElementDofName() const
+{
+ return viewKeyStruct::dofFieldString();
+}
+
+string WellManager::resElementDofName() const
+{
+ if( isCompositional() )
+ return CompositionalMultiphaseBase::viewKeyStruct::elemDofFieldString();
+ else
+ return SinglePhaseBase::viewKeyStruct::elemDofFieldString();
+}
+
+localIndex WellManager::numFluidComponents() const
+{
+ return m_numFluidComponents;
+}
+
+localIndex WellManager::numFluidPhases() const
+{
+ return m_numFluidPhases;
+}
+WellControls & WellManager::getWellControls( WellElementSubRegion const & subRegion )
+{
+ return this->getGroup< WellControls >( subRegion.getWellControlsName());
+}
+
+WellControls const & WellManager::getWellControls( WellElementSubRegion const & subRegion ) const
+{
+ return this->getGroup< WellControls >( subRegion.getWellControlsName());
+}
+
+CompositionalMultiphaseWell & WellManager::getCompositionalMultiphaseWell( WellElementSubRegion const & subRegion )
+{
+ return this->getGroup< CompositionalMultiphaseWell >( subRegion.getWellControlsName());
+}
+
+CompositionalMultiphaseWell const & WellManager::getCompositionalMultiphaseWell( WellElementSubRegion const & subRegion ) const
+{
+ return this->getGroup< CompositionalMultiphaseWell >( subRegion.getWellControlsName());
+}
+void WellManager::initializePostSubGroups()
+{
+#if 0
+ GEOS_MARK_FUNCTION;
+ // Validate constitutive models
+ if( isCompositional() )
+ {
+ DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" );
+ constitutive::ConstitutiveManager const & cm = domain.getConstitutiveManager();
+ CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
+ string const referenceFluidName = flowSolver.referenceFluidModelName();
+ constitutive::MultiFluidBase const & referenceFluid = cm.getConstitutiveRelation< constitutive::MultiFluidBase >( m_referenceFluidModelName );
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel const & mesh,
+ string_array const & regionNames )
+ {
+
+ mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
+ WellElementSubRegion const & subRegion )
+ {
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ constitutive::MultiFluidBase const & fluid = getConstitutiveModel< constitutive::MultiFluidBase >( subRegion, fluidName );
+ WellControls const & wellControls = getWellControls( subRegion );
+ wellControls.validateFluidModel( fluid, referenceFluid );
+ } );
+
+ } );
+ }
+ else
+ {
+ // Single phase validation can be added here in the future
+ }
+#endif
+}
+
+void WellManager::setupDofs( DomainPartition const & domain,
+ DofManager & dofManager ) const
+{
+ map< std::pair< string, string >, string_array > meshTargets;
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const & meshBodyName,
+ MeshLevel const & meshLevel,
+ string_array const & regionNames )
+ {
+ string_array regions;
+ ElementRegionManager const & elementRegionManager = meshLevel.getElemManager();
+ elementRegionManager.forElementRegions< WellElementRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementRegion const & region )
+ {
+ regions.emplace_back( region.getName() );
+ } );
+ auto const key = std::make_pair( meshBodyName, meshLevel.getName());
+ meshTargets[key] = std::move( regions );
+ } );
+
+ dofManager.addField( wellElementDofName(),
+ FieldLocation::Elem,
+ numDofPerWellElement(),
+ meshTargets );
+
+ dofManager.addCoupling( wellElementDofName(),
+ wellElementDofName(),
+ DofManager::Connector::Node );
+}
+
+void WellManager::assembleSystem( real64 const time,
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+
+
+ // 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 );
+
+ 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 );
+ // assemble the accumulation term in the mass balance equations
+ wellControls.assembleWellAccumulationTerms( time, dt, subRegion, dofManager, localMatrix, localRhs );
+ if( wellControls.isWellOpen() )
+ {
+ // assemble the pressure relations between well elements
+ wellControls.assembleWellPressureRelations( time, dt, subRegion, dofManager, localMatrix, localRhs );
+ // assemble well constraint terms
+ wellControls.assembleWellConstraintTerms( time, dt, subRegion, dofManager, localMatrix.toViewConstSizes(), localRhs );
+ // compute the perforation rates (later assembled by the coupled solver)
+ wellControls.computeWellPerforationRates( time, dt, elementRegionManager, subRegion );
+ // assemble the flux terms in the mass balance equations
+ wellControls.assembleWellFluxTerms( time, dt, subRegion, dofManager, localMatrix, localRhs );
+ }
+ } );
+ } );
+
+}
+
+void WellManager::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 );
+ // Intiialize well if it is open
+ // Well state estimated from reservoir conditions
+ if( wellControls.isWellOpen() )
+ {
+ if( !wellControls.getWellState() )
+ {
+ wellControls.setWellState( 1 );
+
+ wellControls.initializeWell( domain, meshLevel, subRegion, time_n );
+ }
+ }
+ else
+ {
+ wellControls.setWellState( 0 );
+ }
+
+ if( wellControls.getWellState())
+ {
+ wellControls.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 );
+ }
+ } );
+ } );
+
+}
+
+void WellManager::resetStateToBeginningOfStep( DomainPartition & domain )
+{
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+
+ ElementRegionManager & elemManager = mesh.getElemManager();
+
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+ WellControls & wellControls = getWellControls( subRegion );
+ wellControls.resetStateToBeginningOfStep( elemManager, subRegion );
+
+
+ } );
+ } );
+}
+
+void WellManager::implicitStepComplete( real64 const & time,
+ real64 const & dt,
+ DomainPartition & domain )
+{
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+
+ ElementRegionManager & elemManager = mesh.getElemManager();
+
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+ WellControls & wellControls = getWellControls( subRegion );
+ wellControls.implicitStepComplete( time, dt, subRegion );
+ } );
+ } );
+}
+
+void WellManager::postRestartInitialization()
+{
+#if 0
+ 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 )
+
+ {
+ WellControls & wellControls = getWell( subRegion );
+ wellControls.postRestartInitialization( );
+
+ } );
+ } );
+#endif
+}
+void WellManager::initializePostInitialConditionsPreSubGroups()
+{
+ PhysicsSolverBase::initializePostInitialConditionsPreSubGroups();
+ 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 )
+ {
+ // reconstruct local connectivity needed for flux calculations
+ subRegion.reconstructLocalConnectivity();
+ WellControls & wellControls = getWellControls( subRegion );
+ wellControls.initializeWellPostInitialConditionsPreSubGroups( subRegion );
+
+
+ } );
+ } );
+}
+void WellManager::setKeepVariablesConstantDuringInitStep( bool const keepVariablesConstantDuringInitStep )
+{
+ 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 )
+
+ {
+ WellControls & wellControls = getWellControls( subRegion );
+ wellControls.setKeepVariablesConstantDuringInitStep( keepVariablesConstantDuringInitStep );
+
+ } );
+ } );
+}
+void WellManager::updateState( DomainPartition & domain )
+{
+ GEOS_MARK_FUNCTION;
+ //tjb
+ real64 maxPhaseVolFrac = 0.0;
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ ElementRegionManager & elemManager = mesh.getElemManager();
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+ WellControls & wellControls = getWellControls( subRegion );
+ if( wellControls.getWellState())
+ {
+
+ real64 const maxRegionPhaseVolFrac = wellControls.updateWellState( elemManager, subRegion );
+
+ maxPhaseVolFrac = LvArray::math::max( maxRegionPhaseVolFrac, maxPhaseVolFrac );
+ }
+ } );
+ } );
+ maxPhaseVolFrac = MpiWrapper::max( maxPhaseVolFrac );
+
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Max well phase volume fraction change = {}",
+ getName(), fmt::format( "{:.{}f}", maxPhaseVolFrac, 4 ) ) );
+
+}
+
+real64
+WellManager::calculateResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ DomainPartition const & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+
+ integer numNorm = 1; // mass balance
+ array1d< real64 > localResidualNorm, wellResidalNorm;
+ array1d< real64 > localResidualNormalizer;
+
+ if( isThermal() )
+ {
+ numNorm = 2; // mass balance and energy balance
+ }
+ localResidualNorm.resize( numNorm );
+
+ localResidualNormalizer.resize( numNorm );
+
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel const & mesh,
+ string_array const & regionNames )
+ {
+
+
+ ElementRegionManager const & elemManager = mesh.getElemManager();
+
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion const & subRegion )
+ {
+
+ WellControls & wellControls = getWellControls( subRegion );
+
+ // step 1: compute the norm in the subRegion
+ if( true ) // tjb wellControls.isWellOpen( ) )
+ {
+ wellResidalNorm = wellControls.calculateLocalWellResidualNorm( time_n,
+ dt,
+ m_nonlinearSolverParameters,
+ subRegion,
+ dofManager,
+ localRhs );
+ for( integer i=0; i localResidualNorm[i] )
+ {
+ localResidualNorm[i] = wellResidalNorm[i];
+ }
+ }
+ }
+ else
+ {
+ for( integer i=0; i const & localSolution )
+{
+ GEOS_MARK_FUNCTION;
+
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+
+ real64 scalingFactor = 1.0;
+ real64 localScalingFactor = 1.0;
+ if( isCompositional() )
+ {
+
+
+ real64 maxDeltaPres = 0.0, maxDeltaCompDens = 0.0, maxDeltaTemp = 0.0;
+ real64 minPresScalingFactor = 1.0, minCompDensScalingFactor = 1.0, minTempScalingFactor = 1.0;
+ real64 localMaxDeltaPres = 0.0, localMaxDeltaCompDens = 0.0, localMaxDeltaTemp = 0.0;
+ real64 localMinPresScalingFactor = 1.0, localMinCompDensScalingFactor = 1.0, localMinTempScalingFactor = 1.0;
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+
+ ElementRegionManager & elemManager = mesh.getElemManager();
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+
+ {
+ CompositionalMultiphaseWell * wellControls = dynamic_cast< CompositionalMultiphaseWell * >(&getWellControls ( subRegion ));
+ localScalingFactor = wellControls->scalingForLocalSystemSolution( subRegion,
+ dofManager,
+ localMaxDeltaPres,
+ localMaxDeltaCompDens,
+ localMaxDeltaTemp,
+ localMinPresScalingFactor,
+ localMinCompDensScalingFactor,
+ localMinTempScalingFactor,
+ localSolution );
+ maxDeltaPres = LvArray::math::max( localMaxDeltaPres, maxDeltaPres );
+ maxDeltaCompDens = LvArray::math::max( localMaxDeltaCompDens, maxDeltaCompDens );
+ maxDeltaTemp = LvArray::math::max( localMaxDeltaTemp, maxDeltaTemp );
+ minPresScalingFactor = LvArray::math::min( localMinPresScalingFactor, minPresScalingFactor );
+ minCompDensScalingFactor = LvArray::math::min( localMinCompDensScalingFactor, minCompDensScalingFactor );
+ minTempScalingFactor = LvArray::math::min( localMinTempScalingFactor, minTempScalingFactor );
+ scalingFactor = LvArray::math::min( localScalingFactor, scalingFactor );
+
+ } );
+ } );
+
+ 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 ) );
+ }
+
+ }
+ else
+ {
+ // Single phase well scaling- not implemented yet
+ scalingFactor=1.0;
+ }
+ return LvArray::math::max( scalingFactor, m_minScalingFactor );
+
+}
+
+bool
+WellManager::checkSystemSolution( DomainPartition & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor )
+{
+ GEOS_MARK_FUNCTION;
+
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+ integer globalCheck = 1;
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+
+ ElementRegionManager & elemManager = mesh.getElemManager();
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+
+ {
+
+ WellControls & wellControls = getWellControls( subRegion );
+ integer localCheck = wellControls.checkWellSystemSolution( subRegion, dofManager, localSolution, scalingFactor );
+ globalCheck = MpiWrapper::min( localCheck );
+ } );
+ } );
+ return globalCheck;
+}
+
+void
+WellManager::applySystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain )
+{
+
+
+ DofManager::CompMask pressureMask( m_numDofPerWellElement, 0, 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(),
+ well::pressure::key(),
+ scalingFactor,
+ pressureMask );
+
+ dofManager.addVectorToField( localSolution,
+ wellElementDofName(),
+ well::connectionRate::key(),
+ scalingFactor,
+ connRateMask );
+ if( isCompositional())
+ {
+ DofManager::CompMask componentMask( m_numDofPerWellElement, 1, numFluidComponents()+1 );
+ dofManager.addVectorToField( localSolution,
+ wellElementDofName(),
+ well::globalCompDensity::key(),
+ scalingFactor,
+ componentMask );
+
+ }
+ if( isThermal() )
+ {
+ DofManager::CompMask temperatureMask( m_numDofPerWellElement, numFluidComponents()+2, numFluidComponents()+3 );
+
+ dofManager.addVectorToField( localSolution,
+ wellElementDofName(),
+ well::temperature::key(),
+ scalingFactor,
+ temperatureMask );
+
+ }
+ // if component density chopping is allowed, some component densities may be negative after the update
+ // these negative component densities are set to zero in this function
+ if( isCompositional() && m_allowCompDensChopping )
+ {
+ chopNegativeDensities( domain );
+ }
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ stdVector< string > propNames;
+ propNames.emplace_back( well::pressure::key() );
+
+ propNames.emplace_back( well::connectionRate::key() );
+ if( isCompositional())
+ {
+ propNames.emplace_back( well::globalCompDensity::key() );
+ }
+ if( isThermal() )
+ {
+ propNames.emplace_back( well::temperature::key() );
+ }
+ // synchronize
+ FieldIdentifiers fieldsToBeSync;
+
+ fieldsToBeSync.addElementFields( propNames,
+ regionNames );
+
+
+ CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync,
+ mesh,
+ domain.getNeighbors(),
+ true );
+ } );
+
+}
+
+void WellManager::chopNegativeDensities( DomainPartition & domain )
+{
+ integer const numComp = m_numFluidComponents;
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+
+ ElementRegionManager & elemManager = mesh.getElemManager();
+
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+ arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank();
+
+ arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens =
+ subRegion.getField< 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;
+ }
+ }
+ }
+ } );
+ } );
+
+ } );
+}
+
+REGISTER_CATALOG_ENTRY( PhysicsSolverBase, WellManager, string const &, Group * const )
+} // namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellManager.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellManager.hpp
new file mode 100644
index 00000000000..3675c0ff623
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellManager.hpp
@@ -0,0 +1,564 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 WellManager.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELL_MANAGER_HPP_
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELL_MANAGER_HPP_
+
+#include "physicsSolvers/PhysicsSolverBase.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp"
+#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp"
+#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp"
+#include "physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp"
+namespace geos
+{
+
+class DomainPartition;
+class WellControls;
+class WellElementSubRegion;
+
+namespace dataRepository
+{
+namespace keys
+{
+static constexpr auto compositionalMultiphaseWell = "CompositionalMultiphaseWell";
+static constexpr auto singlePhaseWell = "SinglePhaseWell";
+}
+}
+/**
+ * @class WellManager
+ *
+ * Base class for well solvers.
+ * Provides some common features
+ */
+class WellManager : public PhysicsSolverBase
+{
+public:
+
+ /// String used to form the solverName used to register single-physics solvers in CoupledSolver
+ static string coupledSolverAttributePrefix() { return "well"; }
+
+ /**
+ * @brief main constructor for Group Objects
+ * @param name the name of this instantiation of Group in the repository
+ * @param parent the parent group of this instantiation of Group
+ */
+ WellManager( const string & name,
+ Group * const parent );
+
+ /// default destructor
+ virtual ~WellManager() override = default;
+
+ /// deleted default constructor
+ WellManager() = delete;
+
+ /// deleted copy constructor
+ WellManager( WellManager const & ) = delete;
+
+ /// default move constructor
+ WellManager( WellManager && ) = default;
+
+ /// deleted assignment operator
+ WellManager & operator=( WellManager const & ) = delete;
+
+ /// deleted move operator
+ WellManager & operator=( WellManager && ) = delete;
+
+ virtual Group * createChild( string const & childKey, string const & childName ) override;
+
+ /// Expand catalog for schema generation
+ virtual void expandObjectCatalogs() override;
+
+ /**
+ * @brief setter for the name of the flow solver (needed to use the flow kernels like UpdateFluid)
+ * @param name the name of the flow solver
+ */
+ void setFlowSolverName( string const & name ) { m_flowSolverName = name; }
+
+ /**
+ * @brief setter for compositional flag
+ * @param compositional the compositional flag
+ */
+ void setCompositional( bool const & isCompositional ) { m_isCompositional = isCompositional; }
+
+ /**
+ * @brief getter for compositional flag
+ * @return the compositional flag
+ */
+ bool isCompositional() const { return m_isCompositional; }
+
+
+ /**
+ * @brief getter for the name of the flow solver (used in UpdateState)
+ * @return a string containing the name of the flow solver
+ */
+ string const & getFlowSolverName() const { return m_flowSolverName; }
+
+
+ /**
+ * @brief name of the node manager in the object catalog
+ * @return string that contains the catalog name to generate a new NodeManager object through the object catalog.
+ */
+ static string catalogName() { return "WellManager"; }
+ /**
+ * @copydoc PhysicsSolverBase::getCatalogName()
+ */
+ string getCatalogName() const override { return catalogName(); }
+
+ virtual void registerDataOnMesh( Group & meshBodies ) override;
+ /**
+ * @brief Get a well solver for a given well element sub-region
+ * @param subRegion the well subRegion whose well solver is requested
+ * @return a reference to the well solver
+ */
+ WellControls & getWell( WellElementSubRegion const & subRegion );
+
+ /**
+ * @brief get the name of DOF defined on well elements
+ * @return name of the DOF field used by derived solver type
+ */
+ string wellElementDofName() const;
+
+ struct viewKeyStruct : PhysicsSolverBase::viewKeyStruct
+ {
+ static constexpr char const * dofFieldString() { return "wellVars"; }
+ static constexpr char const * isThermalString() { return "isThermal"; }
+ static constexpr char const * useMassFlagString() {return "useMass"; }
+ /// @return string for the nextDt targetRegions wrapper
+ static constexpr char const * targetRegionsString() { return "targetRegions"; }
+ static constexpr char const * timeStepFromTablesFlagString() { return "timeStepFromTables"; }
+ static constexpr char const * useTotalMassEquationString() { return "useTotalMassEquation"; }
+ static constexpr char const * allowLocalCompDensChoppingString() { return CompositionalMultiphaseBase::viewKeyStruct::allowLocalCompDensChoppingString(); }
+
+
+ };
+
+ /**
+ * @brief getter for the number of degrees of freedom per well element
+ * @return the number of dofs
+ */
+ localIndex numDofPerWellElement() const;
+
+ /**
+ * @brief getter for the number of degrees of freedom per mesh element
+ * @return the number of dofs
+ */
+ localIndex numDofPerResElement() const;
+
+ /**
+ * @brief getter for iso/thermal switch
+ * @return True if thermal
+ */
+ integer isThermal() const;
+
+
+ /**
+ * @brief get the name of DOF defined on well elements
+ * @return name of the DOF field used by derived solver type
+ */
+ virtual string resElementDofName() const;
+
+ /**
+ * @brief const getter for the number of fluid components
+ * @return the number of fluid components
+ */
+ virtual localIndex numFluidComponents() const;
+
+ /**
+ * @brief const getter for the number of fluid phases
+ * @return the number of fluid phases
+ */
+ virtual localIndex numFluidPhases() const;
+
+ /**
+ * @brief const getter for well total mass equation usage
+ * @return true if total mass equation is used
+ */
+ integer useTotalMassEquation() const { return m_useTotalMassEquation; }
+
+ /**
+ * @brief getter for the well controls associated to this well subRegion
+ * @param subRegion the well subRegion whose controls are requested
+ * @return a reference to the controls
+ */
+ WellControls & getWellControls( WellElementSubRegion const & subRegion );
+
+ /**
+ * @brief const getter for the well controls associated to this well subRegion
+ * @param subRegion the well subRegion whose controls are requested
+ * @return a reference to the const controls
+ */
+ WellControls const & getWellControls( WellElementSubRegion const & subRegion ) const;
+
+ /**
+ * @brief getter for the compositional multiphase well associated to this well subRegion
+ * @param subRegion the well subRegion whose controls are requested
+ * @return a reference to the well
+ */
+ CompositionalMultiphaseWell & getCompositionalMultiphaseWell( WellElementSubRegion const & subRegion );
+
+ /**
+ * @brief const getter for the compositional multiphase well associated to this well subRegion
+ * @param subRegion the well subRegion whose controls are requested
+ * @return a reference to the const well
+ */
+ CompositionalMultiphaseWell const & getCompositionalMultiphaseWell( WellElementSubRegion const & subRegion ) const;
+
+ /**
+ * @brief Selects the active well constraint based on current conditions
+ * @param[in] currentTime the current time
+ * @param[in] currentDt the current time step size
+ * @param[in] coupledIterationNumber the current coupled iteration number
+ * @param[in] domain the domain object
+ * @return the prescribed time step size
+ */
+ void selectWellConstraint( real64 const & time_n,
+ real64 const & dt,
+ integer const coupledIterationNumber,
+ DomainPartition & domain );
+ /* PhysicsSolverBase interfaces */
+
+ /**
+ * @brief function to set the next time step size
+ * @param[in] currentTime the current time
+ * @param[in] currentDt the current time step size
+ * @param[in] domain the domain object
+ * @return the prescribed time step size
+ */
+ virtual real64 setNextDt( real64 const & currentTime,
+ real64 const & currentDt,
+ DomainPartition & domain ) override;
+
+ virtual void setupDofs( DomainPartition const & domain,
+ DofManager & dofManager ) const override;
+
+ /**
+ * @brief function to perform setup for implicit timestep
+ * @param time_n the time at the beginning of the step
+ * @param dt the desired timestep
+ * @param domain the domain partition
+ *
+ * This function should contain any step level initialization required to perform an implicit
+ * step.
+ *
+ * @note This function must be overridden in the derived physics solver in order to use an implict
+ * solution method such as LinearImplicitStep() or NonlinearImplicitStep().
+ */
+ virtual void
+ implicitStepSetup( real64 const & time_n,
+ real64 const & dt,
+ DomainPartition & domain ) override;
+
+
+ /**
+ * @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 localMatrix the system matrix
+ * @param localRhs the system right-hand side vector
+ *
+ * This function assembles the residual and the jacobian of the residual wrt the primary
+ * variables. In a stand alone physics solver, this function will fill a single block in the
+ * block system. However the capability to query the block system structure for any coupled blocks
+ * may be implemented to fill in off diagonal blocks of the system to enable coupling between
+ * solvers.
+ *
+ * @note This function must be overridden in the derived physics solver in order to use an implict
+ * solution method such as LinearImplicitStep() or NonlinearImplicitStep().
+ */
+ virtual void
+ assembleSystem( real64 const time,
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
+
+ virtual void
+ resetStateToBeginningOfStep( DomainPartition & domain ) override;
+
+ virtual void
+ implicitStepComplete( real64 const & time,
+ real64 const & dt,
+ DomainPartition & domain ) override;
+
+ virtual void applyBoundaryConditions( real64 const GEOS_UNUSED_PARAM( time_n ),
+ real64 const GEOS_UNUSED_PARAM( dt ),
+ DomainPartition & GEOS_UNUSED_PARAM( domain ),
+ DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ),
+ arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) override {}
+
+ /**
+ * @brief calculate the norm of the global system residual
+ * @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 localRhs the system right-hand side vector
+ * @return norm of the residual
+ *
+ * This function returns the norm of global residual vector, which is suitable for comparison with
+ * a tolerance.
+ */
+ virtual real64
+ calculateResidualNorm( real64 const & time,
+ real64 const & dt,
+ DomainPartition const & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs ) override;
+ /**
+ * @brief Recompute all dependent quantities from primary variables (including constitutive models)
+ * @param domain the domain containing the mesh and fields
+ */
+ virtual void updateState( DomainPartition & domain ) override;
+
+ /**
+ * @brief Function to determine if the solution vector should be scaled back in order to maintain a known constraint.
+ * @param[in] domain The domain partition.
+ * @param[in] dofManager degree-of-freedom manager associated with the linear system
+ * @param[in] localSolution the solution vector
+ * @return The factor that should be used to scale the solution vector values when they are being applied.
+ */
+ virtual real64
+ scalingForSystemSolution( DomainPartition & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution )override;
+
+ /**
+ * @brief Function to check system solution for physical consistency and constraint violation
+ * @param domain the domain partition
+ * @param dofManager degree-of-freedom manager associated with the linear system
+ * @param localSolution the solution vector
+ * @param scalingFactor factor to scale the solution prior to application
+ * @return true if solution can be safely applied without violating physical constraints, false otherwise
+ *
+ * @note This function must be overridden in the derived physics solver in order to use an implict
+ * solution method such as LinearImplicitStep() or NonlinearImplicitStep().
+ *
+ */
+ virtual bool
+ checkSystemSolution( DomainPartition & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor ) override;
+
+ /**
+ * @brief Function to apply the solution vector to the state
+ * @param dofManager degree-of-freedom manager associated with the linear system
+ * @param localSolution the solution vector
+ * @param scalingFactor factor to scale the solution prior to application
+ * @param dt the timestep
+ * @param domain the domain partition
+ *
+ * This function performs 2 operations:
+ * 1) extract the solution vector for the "blockSystem" parameter, and applies the
+ * contents of the solution vector to the primary variable field data,
+ * 2) perform a synchronization of the primary field variable such that all ghosts are updated,
+ *
+ * The "scalingFactor" parameter allows for the scaled application of the solution vector. For
+ * instance, a line search may apply a negative scaling factor to remove part of the previously
+ * applied solution.
+ *
+ * @note This function must be overridden in the derived physics solver in order to use an implict
+ * solution method such as LinearImplicitStep() or NonlinearImplicitStep().
+ *
+ */
+ virtual void
+ applySystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain ) override;
+
+ /**
+ * @brief Sets all the negative component densities (if any) to zero.
+ * @param domain the physical domain object
+ */
+ void chopNegativeDensities( DomainPartition & domain );
+#if 0
+ /**
+ * @brief calculate the norm of the global system residual
+ * @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 localRhs the system right-hand side vector
+ * @return norm of the residual
+ *
+ * This function returns the norm of global residual vector, which is suitable for comparison with
+ * a tolerance.
+ */
+ virtual real64
+ calculateResidualNorm( real64 const & time,
+ real64 const & dt,
+ DomainPartition const & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs );
+ /**
+ * @brief Function to check system solution for physical consistency and constraint violation
+ * @param domain the domain partition
+ * @param dofManager degree-of-freedom manager associated with the linear system
+ * @param localSolution the solution vector
+ * @param scalingFactor factor to scale the solution prior to application
+ * @return true if solution can be safely applied without violating physical constraints, false otherwise
+ *
+ * @note This function must be overridden in the derived physics solver in order to use an implict
+ * solution method such as LinearImplicitStep() or NonlinearImplicitStep().
+ *
+ */
+ virtual bool
+ checkSystemSolution( DomainPartition & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor );
+
+ /**
+ * @brief Function to determine if the solution vector should be scaled back in order to maintain a known constraint.
+ * @param[in] domain The domain partition.
+ * @param[in] dofManager degree-of-freedom manager associated with the linear system
+ * @param[in] localSolution the solution vector
+ * @return The factor that should be used to scale the solution vector values when they are being applied.
+ */
+ virtual real64
+ scalingForSystemSolution( DomainPartition & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution );
+
+ /**
+ * @brief Function to apply the solution vector to the state
+ * @param dofManager degree-of-freedom manager associated with the linear system
+ * @param localSolution the solution vector
+ * @param scalingFactor factor to scale the solution prior to application
+ * @param dt the timestep
+ * @param domain the domain partition
+ *
+ * This function performs 2 operations:
+ * 1) extract the solution vector for the "blockSystem" parameter, and applies the
+ * contents of the solution vector to the primary variable field data,
+ * 2) perform a synchronization of the primary field variable such that all ghosts are updated,
+ *
+ * The "scalingFactor" parameter allows for the scaled application of the solution vector. For
+ * instance, a line search may apply a negative scaling factor to remove part of the previously
+ * applied solution.
+ *
+ * @note This function must be overridden in the derived physics solver in order to use an implict
+ * solution method such as LinearImplicitStep() or NonlinearImplicitStep().
+ *
+ */
+ virtual void
+ applySystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain );
+
+
+ /**
+ * @brief Recompute all dependent quantities from primary variables (including constitutive models)
+ * @param domain the domain containing the mesh and fields
+ */
+ virtual void updateState( DomainPartition & domain );
+
+ /**
+ * @brief perform cleanup for implicit timestep
+ * @param time the time at the beginning of the step
+ * @param dt the desired timestep
+ * @param domain the domain partition
+ *
+ * This function performs whatever tasks are required to complete an implicit timestep. For
+ * example, the acceptance of the solution will occur during this step, and deallocation of
+ * temporaries will be be performed in this function.
+ *
+ * @note This function must be overridden in the derived physics solver in order to use an implict
+ * solution method such as LinearImplicitStep() or NonlinearImplicitStep().
+ */
+ virtual void
+ implicitStepComplete( real64 const & time,
+ real64 const & dt,
+ DomainPartition & domain ) override;
+
+#endif
+
+ /**
+ * @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 );
+
+
+protected:
+ //virtual void postInputInitialization() override;
+
+ virtual void initializePostSubGroups() override;
+
+ virtual void initializePostInitialConditionsPreSubGroups() override;
+
+ virtual void postRestartInitialization() override final;
+
+
+private:
+
+ /// name of the flow solver
+ string m_flowSolverName;
+
+ /// flag indicating whether mass or molar formulation should be used
+ integer m_useMass;
+
+ /// flag indicating whether total mass equation should be used
+ integer m_useTotalMassEquation;
+
+ /// flag indicating whether thermal formulation is used
+ integer m_isThermal;
+
+ /// flag indicating whether compositional formulation is used
+ bool m_isCompositional;
+
+
+ /// number of phases
+ integer m_numFluidPhases;
+
+ /// number of components
+ integer m_numFluidComponents;
+
+ /// number of degrees of freedom per well element
+ integer m_numDofPerWellElement;
+
+ /// number of degrees of freedom per reservoir element
+ integer m_numDofPerResElement;
+
+ /// minimum value of the scaling factor obtained by enforcing maxCompFracChange
+ real64 m_minScalingFactor;
+
+ /// flag indicating whether local (cell-wise) chopping of negative compositions is allowed
+ integer m_allowCompDensChopping;
+
+ // flag to enable time step selection base on rates/bhp tables coordinates
+ integer m_timeStepFromTables;
+};
+
+}
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELL_MANAGER_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..eadffc21b42
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellMassRateConstraint.cpp
@@ -0,0 +1,75 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 );
+ return ( LvArray::math::abs( currentValue ) > LvArray::math::abs( 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..63f7baa7053
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.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 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 );
+ return ( LvArray::math::abs( currentValue ) > LvArray::math::abs( 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 2e98c2fbaf2..f939d48f704 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp
@@ -36,7 +36,7 @@ using namespace fields;
WellSolverBase::WellSolverBase( string const & name,
Group * const parent )
- : PhysicsSolverBase( name, parent ),
+ : WellControls( name, parent ),
m_numPhases( 0 ),
m_numComponents( 0 ),
m_numDofPerWellElement( 0 ),
@@ -44,6 +44,7 @@ WellSolverBase::WellSolverBase( string const & name,
m_isThermal( 0 ),
m_ratesOutputDir( joinPath( OutputBase::getOutputDirectory(), name + "_rates" ) ),
m_keepVariablesConstantDuringInitStep( false )
+
{
registerWrapper( viewKeyStruct::isThermalString(), &m_isThermal ).
setApplyDefaultValue( 0 ).
@@ -63,40 +64,41 @@ WellSolverBase::WellSolverBase( string const & name,
setInputFlag( dataRepository::InputFlags::OPTIONAL ).
setDescription( "Choose time step to honor rates/bhp tables time intervals" );
+
addLogLevel< logInfo::WellControl >();
}
Group * WellSolverBase::createChild( string const & childKey, string const & childName )
{
+ Group * baseChild = WellControls::createChild( childKey, childName );
+ if( baseChild != nullptr )
+ {
+ return baseChild;
+ }
static std::set< string > const childTypes = {
- keys::wellControls,
+ //keys::wellControls,
PhysicsSolverBase::groupKeyStruct::linearSolverParametersString(),
PhysicsSolverBase::groupKeyStruct::nonlinearSolverParametersString(),
};
GEOS_ERROR_IF( childTypes.count( childKey ) == 0,
CatalogInterface::unknownTypeError( childKey, getDataContext(), childTypes ),
getDataContext() );
- if( childKey == keys::wellControls )
- {
- return ®isterGroup< WellControls >( childName );
- }
- else
- {
- PhysicsSolverBase::createChild( childKey, childName );
- return nullptr;
- }
+
+ PhysicsSolverBase::createChild( childKey, childName );
+ return nullptr;
+
}
void WellSolverBase::expandObjectCatalogs()
{
- createChild( keys::wellControls, keys::wellControls );
+ //createChild( keys::wellControls, keys::wellControls );
}
WellSolverBase::~WellSolverBase() = default;
void WellSolverBase::postInputInitialization()
{
- PhysicsSolverBase::postInputInitialization();
+ WellControls::postInputInitialization();
// 1. Set key dimensions of the problem
m_numDofPerWellElement = m_isThermal ? m_numComponents + 2 : m_numComponents + 1; // 1 pressure connectionRate + temp if thermal
@@ -207,95 +209,67 @@ void WellSolverBase::setupDofs( DomainPartition const & domain,
DofManager::Connector::Node );
}
-void WellSolverBase::setPerforationStatus( real64 const & time_n, DomainPartition & domain )
+
+
+void WellSolverBase::selectWellConstraint( real64 const & time_n,
+ real64 const & dt,
+ const integer coupledIterationNumber,
+ DomainPartition & domain )
{
- FunctionManager & functionManager = FunctionManager::getInstance();
+ GEOS_MARK_FUNCTION;
+ GEOS_UNUSED_VAR( dt );
+ GEOS_UNUSED_VAR( coupledIterationNumber );
- // Set well element/perf status
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const & meshBodyName,
+ MeshLevel & meshLevel,
+ string_array const & regionNames )
{
-
- ElementRegionManager & elemManager = mesh.getElemManager();
- elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
+ 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 );
-
- // Set perforation status
-
- PerforationData & perforationData = *subRegion.getPerforationData();
- string_array const & perfStatusTableName = perforationData.getPerfStatusTableName();
- arrayView1d< integer > perfStatus = perforationData.getLocalPerfStatus();
- // for now set to open
- for( integer i=0; i( perfStatusTableName[i] );
- perfStatus[i]=PerforationData::PerforationStatus::OPEN;
- if( tableFunction->evaluate( &time_n ) < LvArray::NumericLimits< real64 >::epsilon )
+ if( !wellControls.getWellState() )
{
- perfStatus[i]=PerforationData::PerforationStatus::CLOSED;
- }
- }
-
- array1d< localIndex > const perfWellElemIndex = perforationData.getField< fields::perforation::wellElementIndex >();
- // global index local elements (size == subregion.size)
- arrayView1d< globalIndex const > globalWellElementIndex = subRegion.getGlobalWellElementIndex();
-
- arrayView1d< integer const > const elemGhostRank = subRegion.ghostRank();
- array1d< integer > & currentStatus = subRegion.getWellElementStatus();
- // Local elements
- array1d< integer > & localElemStatus = subRegion.getWellLocalElementStatus();
-
- integer numLocalElements = subRegion.getNumLocalElements();
- array1d< integer > segStatus( numLocalElements );
+ wellControls.setWellState( 1 );
- // Local perforations
- for( integer j = 0; j < perforationData.size(); j++ )
- {
- localIndex const iwelem = perfWellElemIndex[j];
- if( elemGhostRank[iwelem] < 0 )
- {
- if( perfStatus[j] )
- {
- segStatus[iwelem] +=1;
- }
+ initializeWell( domain, meshLevel, subRegion, time_n );
}
}
- // Broadcast segment status so all cores have same well status
- subRegion.setElementStatus( segStatus );
- integer numOpenElements = 0;
- array1d< integer > const & updatedStatus = subRegion.getWellElementStatus();
- for( integer i=0; i0 ? wellControls.setWellStatus( time_n, WellControls::Status::OPEN ) : wellControls.setWellStatus( time_n, WellControls::Status::CLOSED );
-
- // Set local well element status array
- for( integer i=0; i const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- string const wellDofKey = dofManager.getKey( wellElementDofName());
+
+
+ // 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 );
+ //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() );
+ assembleWellConstraintTerms( time, dt, subRegion, dofManager, localMatrix.toViewConstSizes(), localRhs );
+ } );
+ } );
+
// then compute the perforation rates (later assembled by the coupled solver)
computePerforationRates( time, dt, domain );
@@ -388,8 +388,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 04fe58112b4..0f999eacb3e 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp
@@ -20,13 +20,13 @@
#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLSOLVERBASE_HPP_
#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLSOLVERBASE_HPP_
-#include "physicsSolvers/PhysicsSolverBase.hpp"
-
+#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
+#include "dataRepository/Group.hpp"
namespace geos
{
class DomainPartition;
-class WellControls;
+
class WellElementSubRegion;
/**
@@ -35,7 +35,7 @@ class WellElementSubRegion;
* Base class for well solvers.
* Provides some common features
*/
-class WellSolverBase : public PhysicsSolverBase
+class WellSolverBase : public WellControls
{
public:
@@ -60,7 +60,7 @@ class WellSolverBase : public PhysicsSolverBase
WellSolverBase( WellSolverBase const & ) = delete;
/// default move constructor
- WellSolverBase( WellSolverBase && ) = default;
+ WellSolverBase( WellSolverBase && ) = delete;
/// deleted assignment operator
WellSolverBase & operator=( WellSolverBase const & ) = delete;
@@ -128,6 +128,12 @@ class WellSolverBase : public PhysicsSolverBase
*/
virtual localIndex numFluidPhases() const = 0;
+ /**
+ * @brief getter for the well associated to this subRegion
+ * @param subRegion the well subRegion whose controls are requested
+ * @return a reference to the well
+ */
+ WellSolverBase & getWell( WellElementSubRegion const & subRegion );
/**
* @brief getter for the well controls associated to this well subRegion
* @param subRegion the well subRegion whose controls are requested
@@ -149,27 +155,63 @@ class WellSolverBase : public PhysicsSolverBase
* @param domain the domain
*/
void setPerforationStatus( real64 const & time_n, DomainPartition & domain );
-
+ void setPerforationStatus( real64 const & time_n, WellElementSubRegion & subRegion );
/**
* @defgroup Solver Interface Functions
*
* These functions provide the primary interface that is required for derived classes
+ * The "Well" versions apply to individual well subRegions, whereas the others apply to all wells
+
*/
/**@{*/
virtual void registerDataOnMesh( Group & meshBodies ) override;
+ 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 set the next time step size
+ * @param[in] currentTime the current time
+ * @param[in] currentDt the current time step size
+ * @param[in] domain the domain object
+ * @return the prescribed time step size
+ */
+ virtual real64 setNextDt( real64 const & currentTime,
+ real64 const & currentDt,
+ DomainPartition & domain ) override;
virtual void setupDofs( DomainPartition const & domain,
DofManager & dofManager ) const override;
- virtual void implicitStepSetup( real64 const & time_n,
- real64 const & dt,
- DomainPartition & domain ) override;
virtual void implicitStepComplete( real64 const & GEOS_UNUSED_PARAM( time_n ),
real64 const & GEOS_UNUSED_PARAM( dt ),
DomainPartition & GEOS_UNUSED_PARAM( domain ) ) override {}
+
virtual void applyBoundaryConditions( real64 const GEOS_UNUSED_PARAM( time_n ),
real64 const GEOS_UNUSED_PARAM( dt ),
DomainPartition & GEOS_UNUSED_PARAM( domain ),
@@ -177,17 +219,23 @@ class WellSolverBase : public PhysicsSolverBase
CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ),
arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) override {}
+ /**
+ * @brief Selects the active well constraint based on current conditions
+ * @param[in] currentTime the current time
+ * @param[in] currentDt the current time step size
+ * @param[in] coupledIterationNumber the current coupled iteration number
+ * @param[in] domain the domain object
+ * @return the prescribed time step size
+ */
+ void selectWellConstraint( real64 const & time_n,
+ real64 const & dt,
+ integer const coupledIterationNumber,
+ DomainPartition & domain );
/**@}*/
/**
- * @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
+ * @copydoc PhysicsSolverBase::assembleSystem()
*/
virtual void assembleSystem( real64 const time,
real64 const dt,
@@ -197,14 +245,15 @@ class WellSolverBase : public PhysicsSolverBase
arrayView1d< real64 > const & localRhs ) override;
/**
- * @brief assembles the flux terms for all connections between well elements
+ * @brief assembles the flux terms for individual well for all connections between well elements
* @param time_n previous time value
* @param dt time step
- * @param domain the physical domain object
+ * @param subRegion the well subregion containing all the primary and dependent fields
* @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 assembleFluxTerms( real64 const & time_n,
real64 const & dt,
DomainPartition & domain,
@@ -226,35 +275,37 @@ class WellSolverBase : public PhysicsSolverBase
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs ) = 0;
+
+
/**
- * @brief assembles the pressure relations at all connections between well elements except at the well head
- * @param time_n time at the beginning of the time step
- * @param dt the time step size
- * @param domain the physical domain object
- * @param dofManager degree-of-freedom manager associated with the linear system
- * @param matrix the system matrix
- * @param rhs the system right-hand side vector
+ * @brief Recompute all dependent quantities from primary variables (including constitutive
+ * models)
+ * @param elemManager the element region manager
+ * @param subRegion the well subRegion containing the well elements and their associated fields
*/
- virtual void assemblePressureRelations( real64 const & time_n,
- real64 const & dt,
- DomainPartition const & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs ) = 0;
-
+ virtual real64 updateWellState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) = 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 void updateState( DomainPartition & domain ) override;
/**
- * @brief Recompute all dependent quantities from primary variables (including constitutive models)
- * @param elemManager the elemManager containing the well
- * @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;
+
+ /**
+ * @brief Recompute all dependent quantities from primary variables (including constitutive
+ * models)
+ * @param elemManager the element region manager
+ * fields
*/
virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) = 0;
+
/**
* @brief Recompute the perforation rates for all the wells
* @param domain the domain containing the mesh and fields
@@ -263,21 +314,14 @@ class WellSolverBase : public PhysicsSolverBase
real64 const & dt,
DomainPartition & domain ) = 0;
- /**
- * @brief function to set the next time step size
- * @param[in] currentTime the current time
- * @param[in] currentDt the current time step size
- * @param[in] domain the domain object
- * @return the prescribed time step size
- */
- virtual real64 setNextDt( real64 const & currentTime,
- real64 const & currentDt,
- 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; }
@@ -287,6 +331,8 @@ 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"; }
+ /// @return string for the targetRegions wrapper
+ static constexpr char const * targetRegionsString() { return "targetRegions"; }
static constexpr char const * fluidNamesString() { return "fluidNames"; }
};
@@ -307,11 +353,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 +368,8 @@ class WellSolverBase : public PhysicsSolverBase
real64 const & dt,
DomainPartition & domain ) = 0;
+
+
/// name of the flow solver
string m_flowSolverName;
@@ -357,6 +400,10 @@ 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;
+
};
}
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp
index b9dfebc799b..1c4b639f4f7 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp
@@ -31,65 +31,7 @@ namespace fields
{
namespace well
-{
-
-DECLARE_FIELD( pressure,
- "pressure",
- array1d< real64 >,
- 0,
- LEVEL_0,
- WRITE_AND_READ,
- "Pressure" );
-
-DECLARE_FIELD( pressure_n,
- "pressure_n",
- array1d< real64 >,
- 0,
- NOPLOT,
- WRITE_AND_READ,
- "Pressure at the previous converged time step" );
-
-DECLARE_FIELD( temperature,
- "temperature",
- array1d< real64 >,
- 0,
- LEVEL_0,
- WRITE_AND_READ,
- "Temperature" );
-
-DECLARE_FIELD( temperature_n,
- "temperature_n",
- array1d< real64 >,
- 0,
- NOPLOT,
- WRITE_AND_READ,
- "Temperature at the previous converged time step" );
-
-DECLARE_FIELD( gravityCoefficient,
- "gravityCoefficient",
- array1d< real64 >,
- 0,
- NOPLOT,
- WRITE_AND_READ,
- "Gravity coefficient (dot product of gravity acceleration by gravity vector)" );
-
-DECLARE_FIELD( pressureScalingFactor,
- "pressureScalingFactor",
- array1d< real64 >,
- 1,
- NOPLOT,
- NO_WRITE,
- "Scaling factors for pressure" );
-
-DECLARE_FIELD( temperatureScalingFactor,
- "temperatureScalingFactor",
- array1d< real64 >,
- 1,
- NOPLOT,
- NO_WRITE,
- "Scaling factors for temperature" );
-
-}
+{}
}
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.cpp
new file mode 100644
index 00000000000..e675af7459e
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.cpp
@@ -0,0 +1,73 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 );
+ return ( LvArray::math::abs( currentValue ) > LvArray::math::abs( 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..229813ee52a
--- /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::connectionRate >();
+ 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::connectionRate >();
+ 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::connectionRate >();
+ 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::connectionRate >();
+ 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 ab153369374..010a9db3e7f 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp
@@ -31,214 +31,6 @@ namespace compositionalMultiphaseWellKernels
using namespace constitutive;
-/******************************** ControlEquationHelper ********************************/
-
-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 )
-{
- // if isViable is true at the end of the following checks, no need to switch
- bool controlIsViable = false;
-
- // The limiting flow rates are treated as upper limits, while the pressure limits
- // are treated as lower limits in production wells and upper limits in injectors.
- // The well changes its mode of control whenever the existing control mode would
- // violate one of these limits.
-
- // Currently, the available constraints are:
- // - Producer: BHP, PHASEVOLRATE
- // - Injector: BHP, TOTALVOLRATE, MASSRATE
-
- // TODO: support GRAT, WRAT, LIQUID for producers and check if any of the active constraint is violated
-
- // BHP control
- if( currentControl == WellControls::Control::BHP )
- {
- // the control is viable if the reference oil rate is below the max rate for producers
- if( isProducer )
- {
- controlIsViable = ( LvArray::math::abs( currentPhaseVolRate[phasePhaseIndex] ) <= LvArray::math::abs( targetPhaseRate ) );
- }
- // the control is viable if the reference total rate is below the max rate for injectors
- else if( inputControl == WellControls::Control::MASSRATE )
- {
- controlIsViable = ( LvArray::math::abs( currentMassRate ) <= LvArray::math::abs( targetMassRate ) );
- }
- else
- {
- controlIsViable = ( LvArray::math::abs( currentTotalVolRate ) <= LvArray::math::abs( targetTotalRate ) );
- }
- }
- else // rate control
- {
- // the control is viable if the reference pressure is below/above the max/min pressure
- if( isProducer )
- {
- // targetBHP specifies a min pressure here
- controlIsViable = ( currentBHP >= targetBHP );
- }
- else
- {
- // targetBHP specifies a max pressure here
- controlIsViable = ( currentBHP <= targetBHP );
- }
- }
-
- if( controlIsViable )
- {
- newControl = currentControl;
- }
- else
- {
- if( isProducer )
- {
- newControl = ( currentControl == WellControls::Control::BHP )
- ? WellControls::Control::PHASEVOLRATE
- : WellControls::Control::BHP;
- }
- else
- {
- if( isZero( targetMassRate ) )
- {
- newControl = ( currentControl == WellControls::Control::BHP )
- ? WellControls::Control::TOTALVOLRATE
- : WellControls::Control::BHP;
- }
- else
- {
- newControl = ( currentControl == WellControls::Control::BHP )
- ? WellControls::Control::MASSRATE
- : WellControls::Control::BHP;
- }
- }
- }
-}
-
-template< integer NC, integer IS_THERMAL >
-GEOS_HOST_DEVICE
-inline
-void
-ControlEquationHelper::
- compute( globalIndex const rankOffset,
- WellControls::Control const currentControl,
- integer const targetPhaseIndex,
- real64 const & targetBHP,
- real64 const & targetPhaseRate,
- real64 const & targetTotalRate,
- real64 const & targetMassRate,
- real64 const & currentBHP,
- arrayView1d< real64 const > const & dCurrentBHP,
- arrayView1d< real64 const > const & currentPhaseVolRate,
- arrayView2d< real64 const > const & dCurrentPhaseVolRate,
-
- real64 const & currentTotalVolRate,
- arrayView1d< real64 const > const & dCurrentTotalVolRate,
- real64 const & massDensity,
- globalIndex const dofNumber,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs )
-{
-
- using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >;
- using Deriv = multifluid::DerivativeOffset;
-
- localIndex const eqnRowIndex = dofNumber + ROFFSET::CONTROL - rankOffset;
- globalIndex dofColIndices[COFFSET_WJ::nDer]{};
- for( integer ic = 0; ic < COFFSET_WJ::nDer; ++ic )
- {
- dofColIndices[ ic ] = dofNumber + ic;
- }
-
- real64 controlEqn = 0;
- real64 dControlEqn[NC+2+IS_THERMAL]{};
-
- // Note: We assume in the computation of currentBHP that the reference elevation
- // is in the top well element. This is enforced by a check in the solver.
- // If we wanted to allow the reference elevation to be outside the top
- // well element, it would make more sense to check the BHP constraint in
- // the well element that contains the reference elevation.
-
- // BHP control
- if( currentControl == WellControls::Control::BHP )
- {
- // control equation is a difference between current BHP and target BHP
- controlEqn = currentBHP - targetBHP;
- dControlEqn[COFFSET_WJ::dP] = dCurrentBHP[Deriv::dP];
- for( integer ic = 0; ic < NC; ++ic )
- {
- dControlEqn[COFFSET_WJ::dC+ic] = dCurrentBHP[Deriv::dC+ic];
- }
- if constexpr ( IS_THERMAL )
-
- dControlEqn[COFFSET_WJ::dT] = dCurrentBHP[Deriv::dT];
-
- }
- // Oil volumetric rate control
- else if( currentControl == WellControls::Control::PHASEVOLRATE )
- {
- controlEqn = currentPhaseVolRate[targetPhaseIndex] - targetPhaseRate;
- dControlEqn[COFFSET_WJ::dP] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dP];
- dControlEqn[COFFSET_WJ::dQ] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dQ];
- for( integer ic = 0; ic < NC; ++ic )
- {
- dControlEqn[COFFSET_WJ::dC+ic] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dC+ic];
- }
- if constexpr ( IS_THERMAL )
- dControlEqn[COFFSET_WJ::dT] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dT];
- }
- // Total volumetric rate control
- else if( currentControl == WellControls::Control::TOTALVOLRATE )
- {
- controlEqn = currentTotalVolRate - targetTotalRate;
- dControlEqn[COFFSET_WJ::dP] = dCurrentTotalVolRate[COFFSET_WJ::dP];
- dControlEqn[COFFSET_WJ::dQ] = dCurrentTotalVolRate[COFFSET_WJ::dQ];
- for( integer ic = 0; ic < NC; ++ic )
- {
- dControlEqn[COFFSET_WJ::dC+ic] = dCurrentTotalVolRate[COFFSET_WJ::dC+ic];
- }
- if constexpr ( IS_THERMAL )
- dControlEqn[COFFSET_WJ::dT] = dCurrentTotalVolRate[COFFSET_WJ::dT];
- }
- // Total mass rate control
- else if( currentControl == WellControls::Control::MASSRATE )
- {
- controlEqn = massDensity*currentTotalVolRate - targetMassRate;
- dControlEqn[COFFSET_WJ::dP] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dP];
- dControlEqn[COFFSET_WJ::dQ] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dQ];
- for( integer ic = 0; ic < NC; ++ic )
- {
- dControlEqn[COFFSET_WJ::dC+ic] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dC+ic];
- }
- if constexpr ( IS_THERMAL )
- dControlEqn[COFFSET_WJ::dT] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dT];
- }
- else
- {
- GEOS_ERROR( "This constraint is not supported in CompositionalMultiphaseWell" );
- }
- localRhs[eqnRowIndex] += controlEqn;
-
- localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex,
- dofColIndices,
- dControlEqn,
- COFFSET_WJ::nDer );
-
-
-}
/******************************** PressureRelationKernel ********************************/
@@ -300,11 +92,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 +104,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 +117,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 +171,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 +427,97 @@ 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 )
+ // Use use defined control type to set initial connection rates
+ WellConstraintBase const * constraint = wellControls.getCurrentConstraint();
+ real64 const constraintVal = constraint->getConstraintValue( time );
+ ConstraintTypeId const controlType = constraint->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] = constraintVal * phaseDens[iwelem][0][targetPhaseIndex];
+ } );
+ }
+ else if( controlType == ConstraintTypeId::TOTALVOLRATE )
+ {
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
+ {
+ connRate[iwelem] = LvArray::math::max( 0.1 * constraintVal * totalDens[iwelem][0], -1e3 );
+ } );
+ }
+ else if( controlType == ConstraintTypeId::MASSRATE )
+ {
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
+ {
+ connRate[iwelem] = constraintVal;
+ } );
+ }
+ else if( controlType == ConstraintTypeId::BHP )
+ {
+ // this assumes phase control present
+ integer const targetPhaseIndex = wellControls.getConstraintPhaseIndex();
+ std::vector< WellConstraintBase * > const constraints = wellControls.getProdRateConstraints();
+ // Use first rate constraint to set initial connection rates
+ real64 const rateVal = constraints[0]->getConstraintValue( time );
+ 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 * rateVal * phaseDens[iwelem][0][targetPhaseIndex], -1e3 );
+ } );
}
- else if( control == WellControls::Control::MASSRATE )
+ }
+ else
+ {
+ // Use use defined control type to set initial connection rates
+ WellConstraintBase const * constraint = wellControls.getCurrentConstraint();
+ real64 const constraintVal = constraint->getConstraintValue( time );
+ ConstraintTypeId const controlType = constraint->getControl();
+ if( controlType == ConstraintTypeId::PHASEVOLRATE )
{
- connRate[iwelem] = targetMassRate;
+ integer const targetPhaseIndex = wellControls.getConstraintPhaseIndex();
+
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
+ {
+ connRate[iwelem] = LvArray::math::max( 0.1 * constraintVal * phaseDens[iwelem][0][targetPhaseIndex], 1e3 );
+ } );
}
- else
+ else if( controlType == ConstraintTypeId::TOTALVOLRATE )
{
- if( isProducer )
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
{
- connRate[iwelem] = targetPhaseRate * phaseDens[iwelem][0][targetPhaseIndex];
- }
- else
+ connRate[iwelem] = constraintVal * totalDens[iwelem][0];
+ } );
+ }
+ else if( controlType == ConstraintTypeId::MASSRATE )
+ {
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
{
- connRate[iwelem] = targetTotalRate * totalDens[iwelem][0];
- }
+ connRate[iwelem] = constraintVal;
+ } );
}
- } );
+ else if( controlType == ConstraintTypeId::BHP )
+ {
+ std::vector< WellConstraintBase * > const constraints = wellControls.getInjRateConstraints();
+ // Use first rate constraint to set initial connection rates
+ real64 const rateVal = constraints[0]->getConstraintValue( time );
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
+ {
+ connRate[iwelem] = LvArray::math::min( 0.1 * rateVal * totalDens[iwelem][0], 1e3 );
+ } );
+ }
+ }
}
-
} // 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..654b6bfbe1a 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp
@@ -39,7 +39,8 @@
#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp"
#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp"
#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
-#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellFields.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 );
}
@@ -1359,7 +1372,7 @@ class FaceBasedAssemblyKernel
m_wellElemDofNumber ( subRegion.getReference< array1d< globalIndex > >( wellDofKey ) ),
m_nextWellElemIndex ( subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString()) ),
m_elemStatus( subRegion.getLocalWellElementStatus() ),
- m_connRate ( subRegion.getField< fields::well::mixtureConnectionRate >() ),
+ m_connRate ( subRegion.getField< fields::well::connectionRate >() ),
m_wellElemCompFrac ( subRegion.getField< fields::well::globalCompFraction >() ),
m_dWellElemCompFrac_dCompDens ( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >() ),
m_localMatrix( localMatrix ),
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/SinglePhasePerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhasePerforationFluxKernels.hpp
index 559245cca72..3a9bbf94565 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhasePerforationFluxKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhasePerforationFluxKernels.hpp
@@ -318,7 +318,7 @@ class PerforationFluxKernelFactory
PerforationData * const perforationData,
ElementSubRegionBase const & subRegion,
constitutive::SingleFluidBase const & fluid,
- ElementRegionManager & elemManager )
+ ElementRegionManager const & elemManager )
{
integer constexpr IS_THERMAL = 0;
using kernelType = PerforationFluxKernel< IS_THERMAL >;
@@ -514,7 +514,7 @@ class PerforationFluxKernelFactory
PerforationData * const perforationData,
ElementSubRegionBase const & subRegion,
SingleFluidBase const & fluid,
- ElementRegionManager & elemManager )
+ ElementRegionManager const & elemManager )
{
integer constexpr IS_THERMAL = 1;
using kernelType = PerforationFluxKernel< IS_THERMAL >;
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 5870c7c919c..7ab06653b68 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..8365d25c946 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp
@@ -20,18 +20,22 @@
#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/WellFields.hpp"
#include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp"
-#include "physicsSolvers/PhysicsSolverBaseKernels.hpp"
+
#include "physicsSolvers/KernelLaunchSelectors.hpp"
namespace geos
@@ -185,13 +189,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 +811,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 +845,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 +863,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 +901,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/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp
index c0c49411f53..32f585ee187 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp
@@ -149,9 +149,8 @@ initializePreSubGroups()
CompositionalMultiphaseBase const * const flowSolver = this->flowSolver();
Base::wellSolver()->setFlowSolverName( flowSolver->getName() );
-
bool const useMassFlow = flowSolver->getReference< integer >( CompositionalMultiphaseBase::viewKeyStruct::useMassFlagString() );
- bool const useMassWell = Base::wellSolver()->template getReference< integer >( CompositionalMultiphaseWell::viewKeyStruct::useMassFlagString() );
+ bool const useMassWell = Base::wellSolver()->template getReference< integer >( WellManager::viewKeyStruct::useMassFlagString() );
GEOS_THROW_IF( useMassFlow != useMassWell,
GEOS_FMT( "The input flag {} must be the same in the flow and well solvers, respectively '{}' and '{}'",
CompositionalMultiphaseBase::viewKeyStruct::useMassFlagString(),
@@ -159,12 +158,27 @@ initializePreSubGroups()
InputError, this->getDataContext(), Base::reservoirSolver()->getDataContext(), Base::wellSolver()->getDataContext() );
bool const isThermalFlow = flowSolver->getReference< integer >( CompositionalMultiphaseBase::viewKeyStruct::isThermalString() );
- bool const isThermalWell = Base::wellSolver()->template getReference< integer >( CompositionalMultiphaseWell::viewKeyStruct::isThermalString() );
+ bool const isThermalWell = Base::wellSolver()->template getReference< integer >( WellManager::viewKeyStruct::isThermalString() );
GEOS_THROW_IF( isThermalFlow != isThermalWell,
GEOS_FMT( "The input flag {} must be the same in the flow and well solvers, respectively '{}' and '{}'",
CompositionalMultiphaseBase::viewKeyStruct::isThermalString(),
Base::reservoirSolver()->getName(), Base::wellSolver()->getName() ),
InputError, this->getDataContext(), Base::reservoirSolver()->getDataContext(), Base::wellSolver()->getDataContext() );
+ DomainPartition & domain = this->template getGroupByPath< DomainPartition >( "/Problem/domain" );
+
+ this->template forDiscretizationOnMeshTargets<>( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ ElementRegionManager & elemManager = mesh.getElemManager();
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
+ WellElementSubRegion const & subRegion )
+ {
+ WellControls & wellControls = Base::wellSolver()->getWellControls( subRegion );
+ wellControls.setFlowSolverName( flowSolver->getName() );
+
+ } );
+ } );
}
template< typename RESERVOIR_SOLVER >
diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp
index b2b1f7a4800..b99975f2ba4 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp
@@ -23,7 +23,7 @@
#include "physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp"
#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp"
-#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellManager.hpp"
namespace geos
{
@@ -31,12 +31,12 @@ namespace geos
/// @tparam RESERVOIR_SOLVER compositional flow or compositional poromechanics solver
template< typename RESERVOIR_SOLVER = CompositionalMultiphaseBase >
class CompositionalMultiphaseReservoirAndWells : public CoupledReservoirAndWellsBase< RESERVOIR_SOLVER,
- CompositionalMultiphaseWell >
+ WellManager >
{
public:
using Base = CoupledReservoirAndWellsBase< RESERVOIR_SOLVER,
- CompositionalMultiphaseWell >;
+ WellManager >;
using Base::getLogLevel;
using Base::m_solvers;
using Base::m_linearSolverParameters;
diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.cpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.cpp
index 1982739401f..3f544f2160d 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.cpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.cpp
@@ -116,7 +116,7 @@ addCouplingNumNonzeros( PhysicsSolverBase const * const solver,
}
bool validateWellPerforations( PhysicsSolverBase const * const reservoirSolver,
- WellSolverBase const * const wellSolver,
+ WellManager const * const wellSolver,
DomainPartition const & domain )
{
std::pair< string, string > badPerforation;
diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp
index 32a67843aec..c7a1f3ea030 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp
@@ -29,7 +29,7 @@
#include "mesh/PerforationFields.hpp"
#include "mesh/DomainPartition.hpp"
#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
-#include "physicsSolvers/fluidFlow/wells/WellSolverBase.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellManager.hpp"
namespace geos
{
@@ -65,7 +65,7 @@ addCouplingNumNonzeros( PhysicsSolverBase const * const solver,
* @param domain the physical domain object
*/
bool validateWellPerforations( PhysicsSolverBase const * const reservoirSolver,
- WellSolverBase const * const wellSolver,
+ WellManager const * const wellSolver,
DomainPartition const & domain );
}
diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp
index 2e86a1fcf2c..d8a12ec18b1 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp
@@ -134,6 +134,29 @@ initializePreSubGroups()
Base::initializePreSubGroups();
SinglePhaseBase const * const flowSolver = this->flowSolver();
Base::wellSolver()->setFlowSolverName( flowSolver->getName() );
+
+ bool const isThermalFlow = flowSolver->getReference< integer >( SinglePhaseBase::viewKeyStruct::isThermalString() );
+ bool const isThermalWell = Base::wellSolver()->template getReference< integer >( WellManager::viewKeyStruct::isThermalString() );
+ GEOS_THROW_IF( isThermalFlow != isThermalWell,
+ GEOS_FMT( "{}: the input flag {} must be the same in the flow and well solvers, respectively '{}' and '{}'",
+ this->getDataContext(), SinglePhaseBase::viewKeyStruct::isThermalString(),
+ Base::reservoirSolver()->getDataContext(), Base::wellSolver()->getDataContext() ),
+ InputError, this->getDataContext(), Base::reservoirSolver()->getDataContext(), Base::wellSolver()->getDataContext() );
+ DomainPartition & domain = this->template getGroupByPath< DomainPartition >( "/Problem/domain" );
+
+ this->template forDiscretizationOnMeshTargets<>( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ ElementRegionManager & elemManager = mesh.getElemManager();
+ elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
+ WellElementSubRegion const & subRegion )
+ {
+ WellControls & wellControls = Base::wellSolver()->getWellControls( subRegion );
+ wellControls.setFlowSolverName( flowSolver->getName() );
+
+ } );
+ } );
}
template< typename RESERVOIR_SOLVER >
diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp
index 0adeee58026..98da0ab2737 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp
@@ -23,7 +23,7 @@
#include "physicsSolvers/multiphysics/CoupledReservoirAndWellsBase.hpp"
#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp"
-#include "physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellManager.hpp"
namespace geos
{
@@ -31,12 +31,12 @@ namespace geos
/// @tparam RESERVOIR_SOLVER single-phase flow or single-phase poromechanics solver
template< typename RESERVOIR_SOLVER = SinglePhaseBase >
class SinglePhaseReservoirAndWells : public CoupledReservoirAndWellsBase< RESERVOIR_SOLVER,
- SinglePhaseWell >
+ WellManager >
{
public:
using Base = CoupledReservoirAndWellsBase< RESERVOIR_SOLVER,
- SinglePhaseWell >;
+ WellManager >;
using Base::m_solvers;
using Base::m_linearSolverParameters;
diff --git a/src/coreComponents/schema/schema.xsd b/src/coreComponents/schema/schema.xsd
index 728d7ec8eff..f1daf74c4c2 100644
--- a/src/coreComponents/schema/schema.xsd
+++ b/src/coreComponents/schema/schema.xsd
@@ -222,18 +222,10 @@
-
-
-
-
-
-
-
-
@@ -363,10 +355,6 @@
-
-
-
-
@@ -511,10 +499,6 @@
-
-
-
-
@@ -543,6 +527,10 @@
+
+
+
+
@@ -1604,26 +1592,10 @@ stress - traction is applied to the faces as specified by the inner product of i
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1632,18 +1604,6 @@ stress - traction is applied to the faces as specified by the inner product of i
-
-
-
-
-
-
-
-
-
-
-
-
@@ -2760,12 +2720,6 @@ Information output from lower logLevels is added with the desired log level
-
-
-
-
-
-
@@ -2802,12 +2756,6 @@ Information output from lower logLevels is added with the desired log level
-
-
-
-
-
-
@@ -2815,6 +2763,16 @@ Information output from lower logLevels is added with the desired log level
+
+
+
+
+
+
+
+
+
+
@@ -3654,144 +3612,6 @@ When set to `all` output both convergence & iteration information to a csv.-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -4187,7 +4007,7 @@ Information output from lower logLevels is added with the desired log level
-
+
@@ -4216,7 +4036,7 @@ When set to `all` output both convergence & iteration information to a csv.-->
-
+
@@ -5697,52 +5517,6 @@ Local- Add jump stabilization on interior of macro elements-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -6228,6 +6002,398 @@ When set to `all` output both convergence & iteration information to a csv.-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/coreComponents/schema/schema.xsd.other b/src/coreComponents/schema/schema.xsd.other
index fc732d195f6..d4ab8f870db 100644
--- a/src/coreComponents/schema/schema.xsd.other
+++ b/src/coreComponents/schema/schema.xsd.other
@@ -351,15 +351,11 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
-
-
-
@@ -526,7 +522,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -570,7 +566,6 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
@@ -607,7 +602,6 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
@@ -615,6 +609,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
+
@@ -867,27 +862,6 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1342,18 +1316,6 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1497,6 +1459,63 @@ A field can represent a physical variable. (pressure, temperature, global compos
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1590,7 +1609,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3504,7 +3523,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3532,7 +3551,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3551,11 +3570,11 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
-
+
@@ -3565,7 +3584,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3575,11 +3594,11 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
-
+
@@ -3589,7 +3608,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3599,7 +3618,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3609,7 +3628,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3639,7 +3658,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3667,7 +3686,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3681,7 +3700,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3693,7 +3712,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3701,11 +3720,11 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
-
+
@@ -3728,7 +3747,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3754,7 +3773,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3775,7 +3794,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3805,7 +3824,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3819,7 +3838,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3850,7 +3869,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+
@@ -3895,7 +3914,7 @@ A field can represent a physical variable. (pressure, temperature, global compos
-
+