diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/immiscibleTwoPhase_GravitySegregation_1d.ats b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/immiscibleTwoPhase_GravitySegregation_1d.ats
new file mode 100644
index 00000000000..b7f470b932f
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/immiscibleTwoPhase_GravitySegregation_1d.ats
@@ -0,0 +1,18 @@
+from geos.ats.test_builder import TestDeck, RestartcheckParameters, generate_geos_tests
+
+restartcheck_params = {}
+restartcheck_params['atol'] = 1.0E-8
+restartcheck_params['rtol'] = 1.0E-8
+
+decks = [
+ TestDeck(
+ name="immiscibleTwoPhase_GravitySegregation_1d",
+ description=
+ 'Test that 2 fluids can be seperated based on gravity.',
+ partitions=((1, 1, 1), ),
+ restart_step=0,
+ check_step=45,
+ restartcheck_params=RestartcheckParameters(**restartcheck_params))
+]
+
+generate_geos_tests(decks)
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/immiscibleTwoPhase_GravitySegregation_1d.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/immiscibleTwoPhase_GravitySegregation_1d.xml
new file mode 100644
index 00000000000..62d4f6cf3bb
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/immiscibleTwoPhase_GravitySegregation_1d.xml
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/initialPressure.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/initialPressure.txt
new file mode 100644
index 00000000000..85a30e13876
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/initialPressure.txt
@@ -0,0 +1,10 @@
+495.0
+485.0
+475.0
+465.0
+455.0
+400.0
+300.0
+200.0
+100.0
+0.0
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/initialSaturation1.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/initialSaturation1.txt
new file mode 100644
index 00000000000..99f11f6b2e7
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/initialSaturation1.txt
@@ -0,0 +1,10 @@
+0
+0
+0
+0
+0
+1
+1
+1
+1
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/initialSaturation2.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/initialSaturation2.txt
new file mode 100644
index 00000000000..1c03b9c1871
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/initialSaturation2.txt
@@ -0,0 +1,10 @@
+1
+1
+1
+1
+1
+0
+0
+0
+0
+0
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/x.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/x.txt
new file mode 100644
index 00000000000..2eb3c4fe4ee
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/x.txt
@@ -0,0 +1 @@
+0.5
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/y.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/y.txt
new file mode 100644
index 00000000000..2eb3c4fe4ee
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/y.txt
@@ -0,0 +1 @@
+0.5
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/z.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/z.txt
new file mode 100644
index 00000000000..f43a1f14d26
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_GravitySegregation_1d/z.txt
@@ -0,0 +1,10 @@
+0.5
+1.5
+2.5
+3.5
+4.5
+5.5
+6.5
+7.5
+8.5
+9.5
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/initialPressure.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/initialPressure.txt
new file mode 100644
index 00000000000..63943bfa00d
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/initialPressure.txt
@@ -0,0 +1,10 @@
+1e7
+1e7
+1e7
+1e7
+1e7
+1e7
+1e7
+1e7
+1e7
+1e7
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/initialSaturation1.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/initialSaturation1.txt
new file mode 100644
index 00000000000..1859fabae78
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/initialSaturation1.txt
@@ -0,0 +1,10 @@
+0.95
+0.95
+0.95
+0.95
+0.95
+0.95
+0.95
+0.05
+0.05
+0.05
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/initialSaturation2.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/initialSaturation2.txt
new file mode 100644
index 00000000000..d113536f2fd
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/initialSaturation2.txt
@@ -0,0 +1,10 @@
+0.05
+0.05
+0.05
+0.05
+0.05
+0.05
+0.05
+0.95
+0.95
+0.95
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/jFunction_linear.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/jFunction_linear.txt
new file mode 100644
index 00000000000..c3dfd50073f
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/jFunction_linear.txt
@@ -0,0 +1,2 @@
+4.33172935918785
+1.66604975353379
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/permx.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/permx.geos
new file mode 100644
index 00000000000..4d47d8fa568
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/permx.geos
@@ -0,0 +1,10 @@
+50
+50
+50
+50
+50
+200
+200
+200
+200
+200
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/permy.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/permy.geos
new file mode 100644
index 00000000000..4d47d8fa568
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/permy.geos
@@ -0,0 +1,10 @@
+50
+50
+50
+50
+50
+200
+200
+200
+200
+200
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/permz.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/permz.geos
new file mode 100644
index 00000000000..4d47d8fa568
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/permz.geos
@@ -0,0 +1,10 @@
+50
+50
+50
+50
+50
+200
+200
+200
+200
+200
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/phaseVolumeFraction_water_linear.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/phaseVolumeFraction_water_linear.txt
new file mode 100644
index 00000000000..0d66ea1aee9
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/phaseVolumeFraction_water_linear.txt
@@ -0,0 +1,2 @@
+0
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/jFunction b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/jFunction
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/jFunction.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/jFunction.txt
new file mode 100644
index 00000000000..72a78a75b85
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/jFunction.txt
@@ -0,0 +1,76 @@
+99.9980934
+17.78445609
+11.20350909
+8.549878542
+7.057769576
+6.082201546
+5.386086427
+4.86006559
+4.446116454
+4.110353325
+3.831547061
+3.595663494
+3.393021946
+3.216710174
+3.061649542
+2.924017691
+2.800877928
+2.68993357
+2.589360389
+2.497689435
+2.413723433
+2.336475912
+2.265126101
+2.198985069
+2.137469915
+2.080083807
+2.02640045
+1.976051821
+1.928718377
+1.884121218
+1.842015737
+1.802186411
+1.764442543
+1.728614745
+1.694551981
+1.662119113
+1.631194842
+1.601669938
+1.573445757
+1.546432977
+1.520550493
+1.495724483
+1.471887601
+1.448978263
+1.426940034
+1.405721104
+1.385273798
+1.365554178
+1.346521677
+1.328138769
+1.310370692
+1.293185194
+1.276552299
+1.260444114
+1.244834648
+1.229699646
+1.215016445
+1.200763848
+1.186921998
+1.173472275
+1.160397205
+1.147680364
+1.135306301
+1.123260469
+1.111529155
+1.100099423
+1.088959056
+1.078096509
+1.067500858
+1.057161765
+1.047069433
+1.03721457
+1.027588362
+1.018182437
+1.008988837
+0.999999998
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/jFunction_linear.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/jFunction_linear.txt
new file mode 100644
index 00000000000..13036f8fd03
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/jFunction_linear.txt
@@ -0,0 +1,2 @@
+100.00
+1.00
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/phaseVolumeFraction_water.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/phaseVolumeFraction_water.txt
new file mode 100644
index 00000000000..f38627d4e85
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/phaseVolumeFraction_water.txt
@@ -0,0 +1,76 @@
+0.001
+0.013333333
+0.026666667
+0.04
+0.053333333
+0.066666667
+0.08
+0.093333333
+0.106666667
+0.12
+0.133333333
+0.146666667
+0.16
+0.173333333
+0.186666667
+0.2
+0.213333333
+0.226666667
+0.24
+0.253333333
+0.266666667
+0.28
+0.293333333
+0.306666667
+0.32
+0.333333333
+0.346666667
+0.36
+0.373333333
+0.386666667
+0.4
+0.413333333
+0.426666667
+0.44
+0.453333333
+0.466666667
+0.48
+0.493333333
+0.506666667
+0.52
+0.533333333
+0.546666667
+0.56
+0.573333333
+0.586666667
+0.6
+0.613333333
+0.626666667
+0.64
+0.653333333
+0.666666667
+0.68
+0.693333333
+0.706666667
+0.72
+0.733333333
+0.746666667
+0.76
+0.773333333
+0.786666667
+0.8
+0.813333333
+0.826666667
+0.84
+0.853333333
+0.866666667
+0.88
+0.893333333
+0.906666667
+0.92
+0.933333333
+0.946666667
+0.96
+0.973333333
+0.986666667
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/phaseVolumeFraction_water_linear.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/phaseVolumeFraction_water_linear.txt
new file mode 100644
index 00000000000..0a269ee3741
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/tables/phaseVolumeFraction_water_linear.txt
@@ -0,0 +1,2 @@
+0.0
+1.0
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/uni_directional_flow_base.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/uni_directional_flow_base.xml
new file mode 100644
index 00000000000..efbd5b34421
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/uni_directional_flow_base.xml
@@ -0,0 +1,293 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/uni_directional_flow_interface_condition.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/uni_directional_flow_interface_condition.xml
new file mode 100644
index 00000000000..41ba4e3ed92
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/uni_directional_flow_interface_condition.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/x.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/x.txt
new file mode 100644
index 00000000000..2eb3c4fe4ee
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/x.txt
@@ -0,0 +1 @@
+0.5
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/y.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/y.txt
new file mode 100644
index 00000000000..2eb3c4fe4ee
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/y.txt
@@ -0,0 +1 @@
+0.5
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/z.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/z.txt
new file mode 100644
index 00000000000..f43a1f14d26
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_case/z.txt
@@ -0,0 +1,10 @@
+0.5
+1.5
+2.5
+3.5
+4.5
+5.5
+6.5
+7.5
+8.5
+9.5
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/1D_ppu_debug.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/1D_ppu_debug.xml
new file mode 100644
index 00000000000..1f7cde919ea
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/1D_ppu_debug.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/1D_ppuc_debug.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/1D_ppuc_debug.xml
new file mode 100644
index 00000000000..f9a19615b34
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/1D_ppuc_debug.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/base_ppu_debug.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/base_ppu_debug.xml
new file mode 100644
index 00000000000..808a59124e8
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/base_ppu_debug.xml
@@ -0,0 +1,416 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/base_ppuc_debug.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/base_ppuc_debug.xml
new file mode 100644
index 00000000000..ec9450a4301
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/base_ppuc_debug.xml
@@ -0,0 +1,422 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageCapPres_Land_left.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageCapPres_Land_left.txt
new file mode 100644
index 00000000000..1f0075201fa
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageCapPres_Land_left.txt
@@ -0,0 +1,16 @@
+1.000000000000000000e+05
+1.161895003862224075e+04
+8.215838362577500448e+03
+6.708203932499360235e+03
+5.809475019311120377e+03
+5.196152422706640209e+03
+4.743416490252559925e+03
+4.391550328268400335e+03
+4.107919181288740219e+03
+3.872983346207419800e+03
+3.674234614174759827e+03
+3.503245248726860154e+03
+3.354101966249680117e+03
+3.222516933177440023e+03
+3.105295017040600214e+03
+3.000000000000000000e+03
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageCapPres_Land_right.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageCapPres_Land_right.txt
new file mode 100644
index 00000000000..ebc19752e4e
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageCapPres_Land_right.txt
@@ -0,0 +1,16 @@
+5.000000000000000000e+04
+5.809475019311120377e+03
+4.107919181288750224e+03
+3.354101966249680117e+03
+2.904737509655560189e+03
+2.598076211353320105e+03
+2.371708245126279962e+03
+2.195775164134200168e+03
+2.053959590644370110e+03
+1.936491673103709900e+03
+1.837117307087379913e+03
+1.751622624363430077e+03
+1.677050983124840059e+03
+1.611258466588720012e+03
+1.552647508520300107e+03
+1.500000000000000000e+03
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageCapPres_Land_x2.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageCapPres_Land_x2.txt
new file mode 100644
index 00000000000..1f0075201fa
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageCapPres_Land_x2.txt
@@ -0,0 +1,16 @@
+1.000000000000000000e+05
+1.161895003862224075e+04
+8.215838362577500448e+03
+6.708203932499360235e+03
+5.809475019311120377e+03
+5.196152422706640209e+03
+4.743416490252559925e+03
+4.391550328268400335e+03
+4.107919181288740219e+03
+3.872983346207419800e+03
+3.674234614174759827e+03
+3.503245248726860154e+03
+3.354101966249680117e+03
+3.222516933177440023e+03
+3.105295017040600214e+03
+3.000000000000000000e+03
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainagePhaseVolFraction_gas_sorted.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainagePhaseVolFraction_gas_sorted.txt
new file mode 100644
index 00000000000..3493bd2e8c5
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainagePhaseVolFraction_gas_sorted.txt
@@ -0,0 +1,16 @@
+0
+0.0533333333333332
+0.106666666666667
+0.16
+0.213333333333333
+0.266666666666667
+0.32
+0.373333333333333
+0.426666666666667
+0.48
+0.533333333333333
+0.586666666666667
+0.64
+0.693333333333333
+0.746666666666667
+0.8
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainagePhaseVolFraction_water.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainagePhaseVolFraction_water.txt
new file mode 100644
index 00000000000..5e2011f62e8
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainagePhaseVolFraction_water.txt
@@ -0,0 +1,16 @@
+0.2
+0.253333333333333
+0.306666666666667
+0.36
+0.413333333333333
+0.466666666666667
+0.52
+0.573333333333333
+0.626666666666667
+0.68
+0.733333333333333
+0.786666666666667
+0.84
+0.893333333333333
+0.946666666666667
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageRelPerm_gas_sorted.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageRelPerm_gas_sorted.txt
new file mode 100644
index 00000000000..a6cf0929af4
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageRelPerm_gas_sorted.txt
@@ -0,0 +1,16 @@
+0
+0.000572839506172836
+0.00442469135802469
+0.0144
+0.0328691358024692
+0.0617283950617284
+0.1024
+0.155832098765432
+0.222498765432099
+0.3024
+0.395061728395062
+0.499535802469136
+0.6144
+0.737758024691358
+0.86723950617284
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageRelPerm_water.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageRelPerm_water.txt
new file mode 100644
index 00000000000..f82875af496
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/drainageRelPerm_water.txt
@@ -0,0 +1,16 @@
+0
+1.97530864197531e-05
+0.00031604938271605
+0.0016
+0.00505679012345679
+0.0123456790123457
+0.0256
+0.0474271604938272
+0.0809086419753086
+0.1296
+0.197530864197531
+0.289204938271605
+0.4096
+0.564167901234568
+0.758834567901235
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionCapPres_Land_left.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionCapPres_Land_left.txt
new file mode 100644
index 00000000000..536327b7165
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionCapPres_Land_left.txt
@@ -0,0 +1,16 @@
+5.650000000000000000e+04
+4.309475019311120377e+03
+2.607919181288740219e+03
+1.854101966249680117e+03
+1.404737509655560189e+03
+1.098076211353320105e+03
+8.717082451262799623e+02
+6.957751641342001676e+02
+5.539595906443801141e+02
+4.364916731037080808e+02
+3.371173070873840061e+02
+2.516226243634259845e+02
+1.770509831248421051e+02
+1.112584665887241044e+02
+5.264750852029601447e+01
+0.000000000000000000e+00
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionCapPres_Land_right.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionCapPres_Land_right.txt
new file mode 100644
index 00000000000..6c02b96afc0
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionCapPres_Land_right.txt
@@ -0,0 +1,16 @@
+2.825000000000000000e+04
+2.154737509655560189e+03
+1.303959590644370110e+03
+9.270509831248400587e+02
+7.023687548277800943e+02
+5.490381056766600523e+02
+4.358541225631399811e+02
+3.478875820671000838e+02
+2.769797953221900570e+02
+2.182458365518540404e+02
+1.685586535436920030e+02
+1.258113121817129922e+02
+8.852549156242105255e+01
+5.562923329436205222e+01
+2.632375426014800723e+01
+0.000000000000000000e+00
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionCapPres_Land_x2.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionCapPres_Land_x2.txt
new file mode 100644
index 00000000000..4d07dae37a4
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionCapPres_Land_x2.txt
@@ -0,0 +1,16 @@
+5.800000000000000000e+04
+5.809475019311120377e+03
+4.107919181288740219e+03
+3.354101966249680117e+03
+2.904737509655560189e+03
+2.598076211353320105e+03
+2.371708245126279962e+03
+2.195775164134200168e+03
+2.053959590644380114e+03
+1.936491673103708081e+03
+1.837117307087384006e+03
+1.751622624363425984e+03
+1.677050983124842105e+03
+1.611258466588724104e+03
+1.552647508520296014e+03
+1.500000000000000000e+03
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionPhaseVolFraction_gas_sorted.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionPhaseVolFraction_gas_sorted.txt
new file mode 100644
index 00000000000..dadfc412179
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionPhaseVolFraction_gas_sorted.txt
@@ -0,0 +1,16 @@
+0.3
+0.333333333333333
+0.366666666666667
+0.4
+0.433333333333333
+0.466666666666667
+0.5
+0.533333333333333
+0.566666666666667
+0.6
+0.633333333333333
+0.666666666666667
+0.7
+0.733333333333333
+0.766666666666667
+0.8
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionPhaseVolFraction_water.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionPhaseVolFraction_water.txt
new file mode 100644
index 00000000000..2ebbac26473
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionPhaseVolFraction_water.txt
@@ -0,0 +1,16 @@
+0.2
+0.233333333333333
+0.266666666666667
+0.3
+0.333333333333333
+0.366666666666667
+0.4
+0.433333333333333
+0.466666666666667
+0.5
+0.533333333333333
+0.566666666666667
+0.6
+0.633333333333333
+0.666666666666667
+0.7
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionRelPerm_gas_sorted.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionRelPerm_gas_sorted.txt
new file mode 100644
index 00000000000..5ba430d7e49
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionRelPerm_gas_sorted.txt
@@ -0,0 +1,16 @@
+2.73691106313441e-48
+0.000572839506172842
+0.0044246913580247
+0.0144
+0.0328691358024692
+0.0617283950617285
+0.1024
+0.155832098765432
+0.222498765432099
+0.3024
+0.395061728395062
+0.499535802469136
+0.6144
+0.737758024691358
+0.86723950617284
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionRelPerm_water.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionRelPerm_water.txt
new file mode 100644
index 00000000000..53281ce3e76
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/consistentHystCurves/imbibitionRelPerm_water.txt
@@ -0,0 +1,16 @@
+0
+1.97530864197531e-05
+0.000316049382716049
+0.0016
+0.00505679012345679
+0.0123456790123457
+0.0256
+0.0474271604938272
+0.0809086419753086
+0.1296
+0.197530864197531
+0.289204938271605
+0.4096
+0.564167901234568
+0.758834567901234
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/initialPressure.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/initialPressure.txt
new file mode 100644
index 00000000000..63943bfa00d
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/initialPressure.txt
@@ -0,0 +1,10 @@
+1e7
+1e7
+1e7
+1e7
+1e7
+1e7
+1e7
+1e7
+1e7
+1e7
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/initialSaturation1.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/initialSaturation1.txt
new file mode 100644
index 00000000000..1859fabae78
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/initialSaturation1.txt
@@ -0,0 +1,10 @@
+0.95
+0.95
+0.95
+0.95
+0.95
+0.95
+0.95
+0.05
+0.05
+0.05
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/initialSaturation2.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/initialSaturation2.txt
new file mode 100644
index 00000000000..d113536f2fd
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/initialSaturation2.txt
@@ -0,0 +1,10 @@
+0.05
+0.05
+0.05
+0.05
+0.05
+0.05
+0.05
+0.95
+0.95
+0.95
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/permx.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/permx.geos
new file mode 100644
index 00000000000..4d47d8fa568
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/permx.geos
@@ -0,0 +1,10 @@
+50
+50
+50
+50
+50
+200
+200
+200
+200
+200
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/permy.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/permy.geos
new file mode 100644
index 00000000000..4d47d8fa568
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/permy.geos
@@ -0,0 +1,10 @@
+50
+50
+50
+50
+50
+200
+200
+200
+200
+200
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/permz.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/permz.geos
new file mode 100644
index 00000000000..4d47d8fa568
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/permz.geos
@@ -0,0 +1,10 @@
+50
+50
+50
+50
+50
+200
+200
+200
+200
+200
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/x.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/x.txt
new file mode 100644
index 00000000000..2eb3c4fe4ee
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/x.txt
@@ -0,0 +1 @@
+0.5
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/y.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/y.txt
new file mode 100644
index 00000000000..2eb3c4fe4ee
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/y.txt
@@ -0,0 +1 @@
+0.5
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/z.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/z.txt
new file mode 100644
index 00000000000..f43a1f14d26
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/1D_performance/z.txt
@@ -0,0 +1,10 @@
+0.5
+1.5
+2.5
+3.5
+4.5
+5.5
+6.5
+7.5
+8.5
+9.5
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/initialPressure.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/initialPressure.txt
new file mode 100644
index 00000000000..6963bb6148c
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/initialPressure.txt
@@ -0,0 +1,1200 @@
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/initialSaturation1.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/initialSaturation1.txt
new file mode 100644
index 00000000000..90ddc12151e
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/initialSaturation1.txt
@@ -0,0 +1,1200 @@
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/initialSaturation2.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/initialSaturation2.txt
new file mode 100644
index 00000000000..d5ef52f254b
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/initialSaturation2.txt
@@ -0,0 +1,1200 @@
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/permx.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/permx.geos
new file mode 100644
index 00000000000..439bd535a86
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/permx.geos
@@ -0,0 +1,1200 @@
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/permy.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/permy.geos
new file mode 100644
index 00000000000..439bd535a86
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/permy.geos
@@ -0,0 +1,1200 @@
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/permz.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/permz.geos
new file mode 100644
index 00000000000..439bd535a86
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/permz.geos
@@ -0,0 +1,1200 @@
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/x.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/x.txt
new file mode 100644
index 00000000000..283fc50e7fb
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/x.txt
@@ -0,0 +1,10 @@
+5.00000000e-01
+1.50000000e+00
+2.50000000e+00
+3.50000000e+00
+4.50000000e+00
+5.50000000e+00
+6.50000000e+00
+7.50000000e+00
+8.50000000e+00
+9.50000000e+00
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/y.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/y.txt
new file mode 100644
index 00000000000..a01763bc5d1
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/y.txt
@@ -0,0 +1,6 @@
+5.00000000e-01
+1.50000000e+00
+2.50000000e+00
+3.50000000e+00
+4.50000000e+00
+5.50000000e+00
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/z.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/z.txt
new file mode 100644
index 00000000000..d122a370abe
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/input/z.txt
@@ -0,0 +1,20 @@
+2.50000000e-01
+7.50000000e-01
+1.25000000e+00
+1.75000000e+00
+2.25000000e+00
+2.75000000e+00
+3.25000000e+00
+3.75000000e+00
+4.25000000e+00
+4.75000000e+00
+5.25000000e+00
+5.75000000e+00
+6.25000000e+00
+6.75000000e+00
+7.25000000e+00
+7.75000000e+00
+8.25000000e+00
+8.75000000e+00
+9.25000000e+00
+9.75000000e+00
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/uni_directional_flow_base.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/uni_directional_flow_base.xml
new file mode 100644
index 00000000000..3982a2b12c6
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/uni_directional_flow_base.xml
@@ -0,0 +1,299 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/uni_directional_flow_interface_condition.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/uni_directional_flow_interface_condition.xml
new file mode 100644
index 00000000000..9bac844ae7b
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_case/uni_directional_flow_interface_condition.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/1D_ppuc_debug.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/1D_ppuc_debug.xml
new file mode 100644
index 00000000000..0301d7ba984
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/1D_ppuc_debug.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/3D_ppu_debug.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/3D_ppu_debug.xml
new file mode 100644
index 00000000000..74e4718eeed
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/3D_ppu_debug.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/3D_ppuc_debug.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/3D_ppuc_debug.xml
new file mode 100644
index 00000000000..1b59a2cc731
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/3D_ppuc_debug.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/base_ppu_debug.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/base_ppu_debug.xml
new file mode 100644
index 00000000000..4c20adbce4a
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/base_ppu_debug.xml
@@ -0,0 +1,413 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/base_ppuc_debug.xml b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/base_ppuc_debug.xml
new file mode 100644
index 00000000000..ee056162423
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/base_ppuc_debug.xml
@@ -0,0 +1,420 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageCapPres_Land_left.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageCapPres_Land_left.txt
new file mode 100644
index 00000000000..1f0075201fa
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageCapPres_Land_left.txt
@@ -0,0 +1,16 @@
+1.000000000000000000e+05
+1.161895003862224075e+04
+8.215838362577500448e+03
+6.708203932499360235e+03
+5.809475019311120377e+03
+5.196152422706640209e+03
+4.743416490252559925e+03
+4.391550328268400335e+03
+4.107919181288740219e+03
+3.872983346207419800e+03
+3.674234614174759827e+03
+3.503245248726860154e+03
+3.354101966249680117e+03
+3.222516933177440023e+03
+3.105295017040600214e+03
+3.000000000000000000e+03
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageCapPres_Land_right.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageCapPres_Land_right.txt
new file mode 100644
index 00000000000..ebc19752e4e
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageCapPres_Land_right.txt
@@ -0,0 +1,16 @@
+5.000000000000000000e+04
+5.809475019311120377e+03
+4.107919181288750224e+03
+3.354101966249680117e+03
+2.904737509655560189e+03
+2.598076211353320105e+03
+2.371708245126279962e+03
+2.195775164134200168e+03
+2.053959590644370110e+03
+1.936491673103709900e+03
+1.837117307087379913e+03
+1.751622624363430077e+03
+1.677050983124840059e+03
+1.611258466588720012e+03
+1.552647508520300107e+03
+1.500000000000000000e+03
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageCapPres_Land_x2.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageCapPres_Land_x2.txt
new file mode 100644
index 00000000000..1f0075201fa
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageCapPres_Land_x2.txt
@@ -0,0 +1,16 @@
+1.000000000000000000e+05
+1.161895003862224075e+04
+8.215838362577500448e+03
+6.708203932499360235e+03
+5.809475019311120377e+03
+5.196152422706640209e+03
+4.743416490252559925e+03
+4.391550328268400335e+03
+4.107919181288740219e+03
+3.872983346207419800e+03
+3.674234614174759827e+03
+3.503245248726860154e+03
+3.354101966249680117e+03
+3.222516933177440023e+03
+3.105295017040600214e+03
+3.000000000000000000e+03
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainagePhaseVolFraction_gas_sorted.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainagePhaseVolFraction_gas_sorted.txt
new file mode 100644
index 00000000000..3493bd2e8c5
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainagePhaseVolFraction_gas_sorted.txt
@@ -0,0 +1,16 @@
+0
+0.0533333333333332
+0.106666666666667
+0.16
+0.213333333333333
+0.266666666666667
+0.32
+0.373333333333333
+0.426666666666667
+0.48
+0.533333333333333
+0.586666666666667
+0.64
+0.693333333333333
+0.746666666666667
+0.8
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainagePhaseVolFraction_water.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainagePhaseVolFraction_water.txt
new file mode 100644
index 00000000000..5e2011f62e8
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainagePhaseVolFraction_water.txt
@@ -0,0 +1,16 @@
+0.2
+0.253333333333333
+0.306666666666667
+0.36
+0.413333333333333
+0.466666666666667
+0.52
+0.573333333333333
+0.626666666666667
+0.68
+0.733333333333333
+0.786666666666667
+0.84
+0.893333333333333
+0.946666666666667
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageRelPerm_gas_sorted.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageRelPerm_gas_sorted.txt
new file mode 100644
index 00000000000..a6cf0929af4
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageRelPerm_gas_sorted.txt
@@ -0,0 +1,16 @@
+0
+0.000572839506172836
+0.00442469135802469
+0.0144
+0.0328691358024692
+0.0617283950617284
+0.1024
+0.155832098765432
+0.222498765432099
+0.3024
+0.395061728395062
+0.499535802469136
+0.6144
+0.737758024691358
+0.86723950617284
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageRelPerm_water.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageRelPerm_water.txt
new file mode 100644
index 00000000000..f82875af496
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/drainageRelPerm_water.txt
@@ -0,0 +1,16 @@
+0
+1.97530864197531e-05
+0.00031604938271605
+0.0016
+0.00505679012345679
+0.0123456790123457
+0.0256
+0.0474271604938272
+0.0809086419753086
+0.1296
+0.197530864197531
+0.289204938271605
+0.4096
+0.564167901234568
+0.758834567901235
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionCapPres_Land_left.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionCapPres_Land_left.txt
new file mode 100644
index 00000000000..536327b7165
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionCapPres_Land_left.txt
@@ -0,0 +1,16 @@
+5.650000000000000000e+04
+4.309475019311120377e+03
+2.607919181288740219e+03
+1.854101966249680117e+03
+1.404737509655560189e+03
+1.098076211353320105e+03
+8.717082451262799623e+02
+6.957751641342001676e+02
+5.539595906443801141e+02
+4.364916731037080808e+02
+3.371173070873840061e+02
+2.516226243634259845e+02
+1.770509831248421051e+02
+1.112584665887241044e+02
+5.264750852029601447e+01
+0.000000000000000000e+00
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionCapPres_Land_right.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionCapPres_Land_right.txt
new file mode 100644
index 00000000000..6c02b96afc0
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionCapPres_Land_right.txt
@@ -0,0 +1,16 @@
+2.825000000000000000e+04
+2.154737509655560189e+03
+1.303959590644370110e+03
+9.270509831248400587e+02
+7.023687548277800943e+02
+5.490381056766600523e+02
+4.358541225631399811e+02
+3.478875820671000838e+02
+2.769797953221900570e+02
+2.182458365518540404e+02
+1.685586535436920030e+02
+1.258113121817129922e+02
+8.852549156242105255e+01
+5.562923329436205222e+01
+2.632375426014800723e+01
+0.000000000000000000e+00
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionCapPres_Land_x2.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionCapPres_Land_x2.txt
new file mode 100644
index 00000000000..4d07dae37a4
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionCapPres_Land_x2.txt
@@ -0,0 +1,16 @@
+5.800000000000000000e+04
+5.809475019311120377e+03
+4.107919181288740219e+03
+3.354101966249680117e+03
+2.904737509655560189e+03
+2.598076211353320105e+03
+2.371708245126279962e+03
+2.195775164134200168e+03
+2.053959590644380114e+03
+1.936491673103708081e+03
+1.837117307087384006e+03
+1.751622624363425984e+03
+1.677050983124842105e+03
+1.611258466588724104e+03
+1.552647508520296014e+03
+1.500000000000000000e+03
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionPhaseVolFraction_gas_sorted.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionPhaseVolFraction_gas_sorted.txt
new file mode 100644
index 00000000000..dadfc412179
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionPhaseVolFraction_gas_sorted.txt
@@ -0,0 +1,16 @@
+0.3
+0.333333333333333
+0.366666666666667
+0.4
+0.433333333333333
+0.466666666666667
+0.5
+0.533333333333333
+0.566666666666667
+0.6
+0.633333333333333
+0.666666666666667
+0.7
+0.733333333333333
+0.766666666666667
+0.8
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionPhaseVolFraction_water.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionPhaseVolFraction_water.txt
new file mode 100644
index 00000000000..2ebbac26473
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionPhaseVolFraction_water.txt
@@ -0,0 +1,16 @@
+0.2
+0.233333333333333
+0.266666666666667
+0.3
+0.333333333333333
+0.366666666666667
+0.4
+0.433333333333333
+0.466666666666667
+0.5
+0.533333333333333
+0.566666666666667
+0.6
+0.633333333333333
+0.666666666666667
+0.7
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionRelPerm_gas_sorted.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionRelPerm_gas_sorted.txt
new file mode 100644
index 00000000000..5ba430d7e49
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionRelPerm_gas_sorted.txt
@@ -0,0 +1,16 @@
+2.73691106313441e-48
+0.000572839506172842
+0.0044246913580247
+0.0144
+0.0328691358024692
+0.0617283950617285
+0.1024
+0.155832098765432
+0.222498765432099
+0.3024
+0.395061728395062
+0.499535802469136
+0.6144
+0.737758024691358
+0.86723950617284
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionRelPerm_water.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionRelPerm_water.txt
new file mode 100644
index 00000000000..53281ce3e76
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/consistentHystCurves/imbibitionRelPerm_water.txt
@@ -0,0 +1,16 @@
+0
+1.97530864197531e-05
+0.000316049382716049
+0.0016
+0.00505679012345679
+0.0123456790123457
+0.0256
+0.0474271604938272
+0.0809086419753086
+0.1296
+0.197530864197531
+0.289204938271605
+0.4096
+0.564167901234568
+0.758834567901234
+1
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/initialPressure.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/initialPressure.txt
new file mode 100644
index 00000000000..6963bb6148c
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/initialPressure.txt
@@ -0,0 +1,1200 @@
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00022072e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00066218e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00110362e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00154508e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00198652e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00242798e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00286942e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00331088e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00375232e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00419378e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00463522e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00507668e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00551812e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00595958e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00640102e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00684248e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00728392e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00772538e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00816682e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
+1.00860828e+07
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/initialSaturation1.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/initialSaturation1.txt
new file mode 100644
index 00000000000..90ddc12151e
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/initialSaturation1.txt
@@ -0,0 +1,1200 @@
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e+00
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
+1.00000000e-02
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/initialSaturation2.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/initialSaturation2.txt
new file mode 100644
index 00000000000..d5ef52f254b
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/initialSaturation2.txt
@@ -0,0 +1,1200 @@
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+0.00000000e+00
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
+9.90000000e-01
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/permx.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/permx.geos
new file mode 100644
index 00000000000..439bd535a86
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/permx.geos
@@ -0,0 +1,1200 @@
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/permy.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/permy.geos
new file mode 100644
index 00000000000..439bd535a86
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/permy.geos
@@ -0,0 +1,1200 @@
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/permz.geos b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/permz.geos
new file mode 100644
index 00000000000..439bd535a86
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/permz.geos
@@ -0,0 +1,1200 @@
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+5.00000000e+01
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
+2.00000000e+02
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/x.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/x.txt
new file mode 100644
index 00000000000..283fc50e7fb
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/x.txt
@@ -0,0 +1,10 @@
+5.00000000e-01
+1.50000000e+00
+2.50000000e+00
+3.50000000e+00
+4.50000000e+00
+5.50000000e+00
+6.50000000e+00
+7.50000000e+00
+8.50000000e+00
+9.50000000e+00
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/y.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/y.txt
new file mode 100644
index 00000000000..a01763bc5d1
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/y.txt
@@ -0,0 +1,6 @@
+5.00000000e-01
+1.50000000e+00
+2.50000000e+00
+3.50000000e+00
+4.50000000e+00
+5.50000000e+00
diff --git a/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/z.txt b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/z.txt
new file mode 100644
index 00000000000..d122a370abe
--- /dev/null
+++ b/inputFiles/immiscibleMultiphaseFlow/immiscibleTwoPhase_interface_conditions/3D_performance/input/z.txt
@@ -0,0 +1,20 @@
+2.50000000e-01
+7.50000000e-01
+1.25000000e+00
+1.75000000e+00
+2.25000000e+00
+2.75000000e+00
+3.25000000e+00
+3.75000000e+00
+4.25000000e+00
+4.75000000e+00
+5.25000000e+00
+5.75000000e+00
+6.25000000e+00
+6.75000000e+00
+7.25000000e+00
+7.75000000e+00
+8.25000000e+00
+8.75000000e+00
+9.25000000e+00
+9.75000000e+00
diff --git a/src/coreComponents/LvArray b/src/coreComponents/LvArray
index 923e15bdfd8..e848125162b 160000
--- a/src/coreComponents/LvArray
+++ b/src/coreComponents/LvArray
@@ -1 +1 @@
-Subproject commit 923e15bdfd8cd05b659cf2cc3c9cdfd76c03a5ee
+Subproject commit e848125162b5b6af76d2dd40c8cfa7fd6ee18cbe
diff --git a/src/coreComponents/common/DataLayouts.hpp b/src/coreComponents/common/DataLayouts.hpp
index cd09af18ef0..0f23039b745 100644
--- a/src/coreComponents/common/DataLayouts.hpp
+++ b/src/coreComponents/common/DataLayouts.hpp
@@ -21,6 +21,7 @@
#define GEOS_COMMON_DATALAYOUTS_HPP_
#include "common/GeosxConfig.hpp"
+#include "common/DataTypes.hpp"
#include "LvArray/src/Array.hpp"
#include "RAJA/RAJA.hpp"
diff --git a/src/coreComponents/constitutive/CMakeLists.txt b/src/coreComponents/constitutive/CMakeLists.txt
index 6af439fe23f..bfb182dfe89 100644
--- a/src/coreComponents/constitutive/CMakeLists.txt
+++ b/src/coreComponents/constitutive/CMakeLists.txt
@@ -27,12 +27,14 @@ set( constitutive_headers
ConstitutivePassThruHandler.hpp
ExponentialRelation.hpp
NullModel.hpp
+ KilloughHysteresis.hpp
capillaryPressure/BrooksCoreyCapillaryPressure.hpp
capillaryPressure/CapillaryPressureBase.hpp
capillaryPressure/CapillaryPressureFields.hpp
capillaryPressure/InverseCapillaryPressure.hpp
capillaryPressure/JFunctionCapillaryPressure.hpp
capillaryPressure/TableCapillaryPressure.hpp
+ capillaryPressure/TableCapillaryPressureHysteresis.hpp
capillaryPressure/TableCapillaryPressureHelpers.hpp
capillaryPressure/VanGenuchtenCapillaryPressure.hpp
capillaryPressure/CapillaryPressureSelector.hpp
@@ -226,11 +228,13 @@ set( constitutive_sources
ConstitutiveBase.cpp
ConstitutiveManager.cpp
NullModel.cpp
+ KilloughHysteresis.cpp
capillaryPressure/BrooksCoreyCapillaryPressure.cpp
capillaryPressure/CapillaryPressureBase.cpp
capillaryPressure/InverseCapillaryPressure.cpp
capillaryPressure/JFunctionCapillaryPressure.cpp
capillaryPressure/TableCapillaryPressure.cpp
+ capillaryPressure/TableCapillaryPressureHysteresis.cpp
capillaryPressure/TableCapillaryPressureHelpers.cpp
capillaryPressure/VanGenuchtenCapillaryPressure.cpp
contact/BartonBandis.cpp
@@ -369,6 +373,7 @@ if( ENABLE_PVTPackage )
endif()
if (ENABLE_HPCREACT)
+ if( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/HPCReact/CMakeLists.txt" )
set( constitutive_headers
${constitutive_headers}
fluid/reactivefluid/ReactiveFluidSelector.hpp
@@ -383,8 +388,9 @@ if (ENABLE_HPCREACT)
${constitutive_sources}
fluid/reactivefluid/ReactiveSinglePhaseFluid.cpp
)
- add_subdirectory( HPCReact )
- list( APPEND dependencyList hpcReact )
+ add_subdirectory( HPCReact )
+ list( APPEND dependencyList hpcReact )
+ endif()
endif()
geos_decorate_link_dependencies( LIST decoratedDependencies
diff --git a/src/coreComponents/constitutive/KilloughHysteresis.cpp b/src/coreComponents/constitutive/KilloughHysteresis.cpp
new file mode 100644
index 00000000000..cb1d7b2b6be
--- /dev/null
+++ b/src/coreComponents/constitutive/KilloughHysteresis.cpp
@@ -0,0 +1,144 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University
+ * Copyright (c) 2018-2020 TotalEnergies
+ * Copyright (c) 2019- GEOSX Contributors
+ * All rights reserved
+ *
+ * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+
+/***
+ * @file KilloughHysteresis.cpp
+ */
+
+#include "KilloughHysteresis.hpp"
+
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+namespace constitutive
+{
+
+
+void KilloughHysteresis::postProcessInput( real64 const & jerauldParam_a, real64 const & jerauldParam_b,
+ real64 const & killoughCurvatureParamRelPerm,
+ real64 const & killoughCurvatureParamPc )
+{
+ GEOS_THROW_IF( jerauldParam_a < 0,
+ GEOS_FMT( "{}: the parameter {} must be positive",
+ catalogName(),
+ viewKeyStruct::jerauldParameterAString() ),
+ InputError );
+
+ GEOS_THROW_IF( jerauldParam_b < 0,
+ GEOS_FMT( "{}: the paramater {} must be postitive",
+ catalogName(),
+ viewKeyStruct::jerauldParameterBString() ),
+ InputError );
+
+ GEOS_THROW_IF( killoughCurvatureParamRelPerm < 0,
+ GEOS_FMT( "{}: the paramater {} must be postitive",
+ catalogName(),
+ viewKeyStruct::killoughCurvatureParameterRelPermString() ),
+ InputError );
+
+ GEOS_THROW_IF( killoughCurvatureParamPc < 0,
+ GEOS_FMT( "{}: the paramater {} must be postitive",
+ catalogName(),
+ viewKeyStruct::killoughCurvatureParameterPcString() ),
+ InputError );
+
+}
+
+
+
+//TODO
+void KilloughHysteresis::computeLandCoefficient( KilloughHysteresis::HysteresisCurve const & hcurve,
+ real64 & landParam )
+{
+
+ // Note: for simplicity, the notations are taken from IX documentation (although this breaks our phaseVolFrac naming convention)
+
+ // Step 1: Land parameter for the wetting phase
+ if( hcurve.isWetting() )
+ {
+ real64 const Scrd = hcurve.oppositeBoundPhaseVolFraction;
+ real64 const Smxd = hcurve.drainageExtremaPhaseVolFraction;
+ real64 const Smxi = hcurve.imbibitionExtremaPhaseVolFraction;
+ real64 const Swc = Scrd;
+ GEOS_THROW_IF( (Smxi - Smxd) > 0,
+ GEOS_FMT( "{}: For wetting phase hysteresis, imbibition end-point saturation Smxi( {} ) must be smaller than the drainage saturation end-point Smxd( {} ).\n"
+ "Crossing relative permeability curves.\n",
+ catalogName(),
+ Smxi,
+ Smxd ),
+ InputError );
+
+ landParam = ( Smxd - Swc ) / LvArray::math::max( KilloughHysteresis::minScriMinusScrd, ( Smxd - Smxi ) ) - 1.0;
+ }
+ else
+ // Step 2: Land parameter for the non-wetting phase
+
+ {
+ real64 const Smx = hcurve.oppositeBoundPhaseVolFraction;
+ real64 const Scrd = hcurve.drainageExtremaPhaseVolFraction;
+ real64 const Scri = hcurve.imbibitionExtremaPhaseVolFraction;
+ GEOS_THROW_IF( (Scrd - Scri) > 0,
+ GEOS_FMT( "{}: For non-wetting phase hysteresis, drainage trapped saturation Scrd( {} ) must be smaller than the imbibition saturation Scri( {} ).\n"
+ "Crossing relative permeability curves.\n",
+ catalogName(),
+ Scrd,
+ Scri ),
+ InputError );
+
+ landParam = ( Smx - Scrd ) / LvArray::math::max( KilloughHysteresis::minScriMinusScrd, ( Scri - Scrd ) ) - 1.0;
+ }
+}
+
+GEOS_HOST_DEVICE
+void
+KilloughHysteresis::
+ computeTrappedCriticalPhaseVolFraction( HysteresisCurve const & hcurve,
+ real64 const & Shy,
+ real64 const & landParam,
+ real64 const & jerauldParam_a,
+ real64 const & jerauldParam_b,
+ real64 & Scrt )
+{
+
+ if( hcurve.isWetting())
+ {
+ //unpack values
+ real64 const Smxd = hcurve.drainageExtremaPhaseVolFraction;
+ real64 const Swc = hcurve.oppositeBoundPhaseVolFraction;
+
+ real64 const A = 1 + jerauldParam_a * (Shy - Swc);
+ real64 const numerator = Shy - Smxd;
+ real64 const denom = A + landParam * pow((Smxd - Shy) / (Smxd - Swc), 1 + jerauldParam_b / landParam );
+ Scrt = Smxd + numerator / denom;
+ }
+ else
+ {
+ //unpack values
+ real64 const Scrd = hcurve.drainageExtremaPhaseVolFraction;
+ real64 const Smx = hcurve.oppositeBoundPhaseVolFraction;
+
+ real64 const A = 1 + jerauldParam_a * (Smx - Shy);
+ real64 const numerator = Shy - Scrd;
+ real64 const denom = A + landParam * pow((Shy - Scrd) / (Smx - Scrd), 1 + jerauldParam_b / landParam );
+ Scrt = LvArray::math::max( 0.0,
+ Scrd + numerator / denom ); // trapped critical saturation from equation 2.162
+ }
+
+}
+
+}//end namespace
+}//end namespace
diff --git a/src/coreComponents/constitutive/KilloughHysteresis.hpp b/src/coreComponents/constitutive/KilloughHysteresis.hpp
new file mode 100644
index 00000000000..09062ee9bf7
--- /dev/null
+++ b/src/coreComponents/constitutive/KilloughHysteresis.hpp
@@ -0,0 +1,179 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University
+ * Copyright (c) 2018-2020 TotalEnergies
+ * Copyright (c) 2019- GEOSX Contributors
+ * All rights reserved
+ *
+ * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+
+/**
+ * @file TableRelativePermeabilityHysteresis.hpp
+ */
+
+#ifndef GEOS_KILLOUGHHYSTERESIS_HPP
+#define GEOS_KILLOUGHHYSTERESIS_HPP
+
+#include "constitutive/ConstitutiveBase.hpp"
+#include "functions/TableFunction.hpp"
+
+#include "relativePermeability/Layouts.hpp"
+#include "capillaryPressure/Layouts.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+namespace constitutive
+{
+
+/***
+ * @brief KilloughHysteresis is designed to hold Killough hystereis model parameters and
+ * be in charge of all compuration related to this model (trapped Saturation,Land Coefficient?)
+ */
+
+
+
+//should be up to constitutiveBase or some new SCALConstitutiveBase but for now let's POC on relativePermeabilityBase
+class KilloughHysteresis
+{
+public:
+
+ static constexpr real64 minScriMinusScrd = 1e-12;
+ /// To avoid frequent changes from drainage to imbibition and vice versa, we use this buffer
+ static constexpr real64 flowReversalBuffer = 1e-12;
+
+ struct PhaseWettability
+ {
+ enum : integer
+ {
+ WETTING = 0,
+ NONWETTING = 1
+ };
+ };
+
+ /**
+ * @brief struct to represent hysteresis curves (relperm or capillary pressure)
+ * whether they are wetting or non wetting, storing key point as pairs of
+ * saturations and value, being either the relperm value (S,kr) or capillary pressure value (S,pc).
+ * this way we can tell wetting curve from non wetting by the ordering of drainage/imbibition key values.
+ * Indeed if imbibition comes at lower saturation than drainage then it is wetting curve, on the opposite
+ * if drainage comes before imbibition this is a non-wetting hysteresis. This is completed by an opposite
+ * point that is either the connate wetting saturation Swc or the maximum non wetting saturation Sgmax.
+ * @param oppositeBoundPhaseVolFraction represents either Swc or Sgmax depending if a wetting curve or nonwetting is described
+ * @param imbibitionExtremaPhaseVolFraction represents in wetting case the imibibition max and in non-wetting the imbibition residual
+ * @param drainageExtremaPhaseVolFraction represents in wetting case the drainage max and in non-wetting the drainage residual
+ * @param oppositeBoundSCALValue represents the associate relperm or capillary pressure value
+ * @param imbibitionExtremaSCALValue represents the associate relperm or capillary pressure value
+ * @param drainageExtremaSCALValue represents the associate relperm or capillary pressure value
+ */
+
+ struct HysteresisCurve
+ {
+ real64 oppositeBoundPhaseVolFraction = -1.;
+ real64 imbibitionExtremaPhaseVolFraction = -1.;
+ real64 drainageExtremaPhaseVolFraction = -1.;
+
+ real64 oppositeBoundSCALValue = -1.;
+ real64 imbibitionExtremaSCALValue = -1.;
+ real64 drainageExtremaSCALValue = -1.;
+
+ HysteresisCurve() = default;
+
+ HysteresisCurve( std::pair< real64, real64 > const & opp, std::pair< real64, real64 > const & imbE, std::pair< real64, real64 > const & drainE )
+ {
+ setPoints( opp, imbE, drainE );
+ }
+
+ void setPoints( std::pair< real64, real64 > const & opp, std::pair< real64, real64 > const & imbE, std::pair< real64, real64 > const & drainE )
+ {
+ oppositeBoundPhaseVolFraction = opp.first;
+ imbibitionExtremaPhaseVolFraction = imbE.first;
+ drainageExtremaPhaseVolFraction = drainE.first;
+
+ oppositeBoundSCALValue = opp.second;
+ imbibitionExtremaSCALValue = imbE.second;
+ drainageExtremaSCALValue = drainE.second;
+ }
+
+ //tODO (jacques) check if relevant to invert relation with same SCAL value // might be misleading for kr
+ HysteresisCurve toWetting() const
+ {
+ if( !isWetting())
+ return HysteresisCurve( {1.-oppositeBoundPhaseVolFraction, oppositeBoundSCALValue},
+ {1.- imbibitionExtremaPhaseVolFraction, imbibitionExtremaSCALValue},
+ {1.-drainageExtremaPhaseVolFraction, drainageExtremaSCALValue} );
+ else
+ return *this;
+ }
+
+ HysteresisCurve toNonWetting() const
+ {
+ if( isWetting())
+ return HysteresisCurve( {1.-oppositeBoundPhaseVolFraction, oppositeBoundSCALValue},
+ {1.-imbibitionExtremaPhaseVolFraction, imbibitionExtremaSCALValue},
+ {1.-drainageExtremaPhaseVolFraction, drainageExtremaSCALValue} );
+ else
+ return *this;
+ }
+
+ bool isWetting() const
+ {
+ return ((drainageExtremaPhaseVolFraction > oppositeBoundPhaseVolFraction) ? PhaseWettability::WETTING : PhaseWettability::NONWETTING) == PhaseWettability::WETTING;
+ }
+ bool isZero() const
+ {
+ return (oppositeBoundPhaseVolFraction <= 0.0) && (imbibitionExtremaPhaseVolFraction <= 0.0) && (drainageExtremaPhaseVolFraction <= 0.0);
+ }
+
+ };
+
+// void setRelPermParameters( real64 const & jerauldA, real64 const & jerauldB, real64 const & relpermCurv );
+
+ static std::string catalogName() { return "KilloughHysteresis"; }
+
+ static void postProcessInput( real64 const & jerauldParam_a, real64 const & jerauldParam_b,
+ real64 const & killoughCurvatureParamRelPerm,
+ real64 const & killoughCurvatureParamPc );
+
+ GEOS_HOST_DEVICE
+ static void computeLandCoefficient( HysteresisCurve const & hcruve, real64 & landParam );
+ /**
+ * @brief Function computing the trapped critical phase volume fraction
+ * @param[in] hcurve the hysteresis curve to be used and dispatched on
+ * @param[in] Shy the max historical phase volume fraction
+ * @param[in] landParam Land trapping parameter
+ * @param[in] jerauldParam_a jerauld expononent
+ * @param[in] jerauldParam_b jerauld expononent
+ * @param[out] Scrt the trapped critical phase volume fraction
+ */
+ GEOS_HOST_DEVICE
+ static void computeTrappedCriticalPhaseVolFraction( HysteresisCurve const & hcurve,
+ real64 const & Shy,
+ real64 const & landParam,
+ real64 const & jerauldParam_a,
+ real64 const & jerauldParam_b,
+ real64 & Scrt );
+
+ struct viewKeyStruct
+ {
+ static constexpr char const * jerauldParameterAString() { return "jerauldParameterA"; }
+ static constexpr char const * jerauldParameterBString() { return "jerauldParameterB"; }
+
+ static constexpr char const * killoughCurvatureParameterRelPermString() { return "killoughCurvatureParameterRelPerm"; }
+ static constexpr char const * killoughCurvatureParameterPcString() { return "killoughCurvatureParameterPc"; }
+ };
+
+};
+
+}
+
+}
+
+#endif //GEOS_KILLOUGHHYSTERESIS_HPP
diff --git a/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.cpp b/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.cpp
index 342da282b58..73835e6de41 100644
--- a/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.cpp
+++ b/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.cpp
@@ -115,6 +115,7 @@ BrooksCoreyCapillaryPressure::createKernelWrapper()
m_volFracScale,
m_phaseTypes,
m_phaseOrder,
+ m_phaseTrappedVolFrac,
m_phaseCapPressure,
m_dPhaseCapPressure_dPhaseVolFrac );
}
diff --git a/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.hpp b/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.hpp
index 39d93e48858..e0c971492b2 100644
--- a/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.hpp
+++ b/src/coreComponents/constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.hpp
@@ -39,10 +39,12 @@ class BrooksCoreyCapillaryPressureUpdate final : public CapillaryPressureBaseUpd
real64 const volFracScale,
arrayView1d< integer const > const & phaseTypes,
arrayView1d< integer const > const & phaseOrder,
+ arrayView3d< real64, cappres::USD_CAPPRES > const & phaseTrapped,
arrayView3d< real64, cappres::USD_CAPPRES > const & phaseCapPressure,
arrayView4d< real64, cappres::USD_CAPPRES_DS > const & dPhaseCapPressure_dPhaseVolFrac )
: CapillaryPressureBaseUpdate( phaseTypes,
phaseOrder,
+ phaseTrapped,
phaseCapPressure,
dPhaseCapPressure_dPhaseVolFrac ),
m_phaseMinVolumeFraction( phaseMinVolumeFraction ),
@@ -57,6 +59,11 @@ class BrooksCoreyCapillaryPressureUpdate final : public CapillaryPressureBaseUpd
arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const;
+ GEOS_HOST_DEVICE
+ void computeInv( arraySlice1d< real64, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const;
+
GEOS_HOST_DEVICE
virtual void update( localIndex const k,
localIndex const q,
@@ -80,14 +87,32 @@ class BrooksCoreyCapillaryPressureUpdate final : public CapillaryPressureBaseUpd
real64 & phaseCapPressure,
real64 & dPhaseCapPressure_dVolFrac );
+
+ GEOS_HOST_DEVICE
+ GEOS_FORCE_INLINE
+ static void
+ evaluateBrooksCoreyFunctionInv( real64 const phaseCapPressure,
+ int const ip,
+ real64 const volFracScaleInv,
+ real64 const exponentInv,
+ real64 const entryPressure,
+ real64 const maxCapPres_eps,
+ real64 const phaseMinVolumeFraction,
+ arrayView1d< integer const > const phaseOrder,
+ real64 & phaseVolFraction,
+ real64 & dPhaseCapPressure_dVolFrac );
+
arrayView1d< real64 const > m_phaseMinVolumeFraction;
arrayView1d< real64 const > m_phaseCapPressureExponentInv;
arrayView1d< real64 const > m_phaseEntryPressure;
real64 m_capPressureEpsilon;
real64 m_volFracScale;
+
};
+
+
class BrooksCoreyCapillaryPressure : public CapillaryPressureBase
{
public:
@@ -169,11 +194,14 @@ BrooksCoreyCapillaryPressureUpdate::
// compute first gas-oil capillary pressure as a function of gas-phase vol fraction
integer const ip_gas = m_phaseOrder[CapillaryPressureBase::PhaseType::GAS];
- if( ip_gas >= 0 )
+ integer const ip_oil = m_phaseOrder[CapillaryPressureBase::PhaseType::OIL];
+
+ GEOS_UNUSED_VAR( ip_gas );
+ if( ip_oil >= 0 )
{
- real64 const volFracScaled = (phaseVolFraction[ip_gas] - m_phaseMinVolumeFraction[ip_gas]) * volFracScaleInv;
- real64 const exponentInv = m_phaseCapPressureExponentInv[ip_gas];
- real64 const entryPressure = -m_phaseEntryPressure[ip_gas]; // for gas capillary pressure, take the opposite of the
+ real64 const volFracScaled = (phaseVolFraction[ip_oil] - m_phaseMinVolumeFraction[ip_oil]) * volFracScaleInv;
+ real64 const exponentInv = m_phaseCapPressureExponentInv[ip_oil];
+ real64 const entryPressure = -m_phaseEntryPressure[ip_oil]; // for gas capillary pressure, take the opposite of the
// BC function
real64 const wettingVolFracScaled = 1-volFracScaled;
@@ -184,11 +212,103 @@ BrooksCoreyCapillaryPressureUpdate::
exponentInv,
entryPressure,
eps,
- phaseCapPres[ip_gas],
- dPhaseCapPres_dPhaseVolFrac[ip_gas][ip_gas] );
+ phaseCapPres[ip_oil],
+ dPhaseCapPres_dPhaseVolFrac[ip_oil][ip_oil] );
}
}
+GEOS_HOST_DEVICE
+inline void
+BrooksCoreyCapillaryPressureUpdate::
+ computeInv( arraySlice1d< real64, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const
+{
+ LvArray::forValuesInSlice( dPhaseCapPres_dPhaseVolFrac, []( real64 & val ){ val = 0.0; } );
+
+ real64 const volFracScaleInv = 1.0 / m_volFracScale;
+
+ // the Brooks-Corey model does not support volFracScaled = 0,
+ // hence we need an epsilon value to avoid a division by zero
+ // TODO: for S < epsilon, replace the original unbounded BC curve with a bounded power-law extension
+ real64 const eps = m_capPressureEpsilon;
+
+
+ // compute first water-oil capillary pressure as a function of water-phase vol fraction
+ integer const ip_water = m_phaseOrder[CapillaryPressureBase::PhaseType::WATER];
+ integer const ip_gas = m_phaseOrder[CapillaryPressureBase::PhaseType::GAS];
+ if( ip_water >= 0 )
+ {
+ real64 const volFracScaled_eps = (eps - m_phaseMinVolumeFraction[ip_water]) * volFracScaleInv;
+ real64 const exponentInv = m_phaseCapPressureExponentInv[ip_water];
+ real64 const entryPressure = m_phaseEntryPressure[ip_water];
+
+ real64 const wettingVolFracScaled_eps = volFracScaled_eps;
+ real64 const dWettingVolFracScaled_dVolFrac = volFracScaleInv;
+
+ real64 maxCapPres_eps = 0.0;
+ real64 max_dpc_eps = 0.0;
+
+ evaluateBrooksCoreyFunction( wettingVolFracScaled_eps,
+ dWettingVolFracScaled_dVolFrac,
+ exponentInv,
+ entryPressure,
+ eps,
+ maxCapPres_eps,
+ max_dpc_eps );
+
+ evaluateBrooksCoreyFunctionInv( phaseCapPres[ip_water],
+ ip_water,
+ volFracScaleInv,
+ exponentInv,
+ entryPressure,
+ maxCapPres_eps,
+ m_phaseMinVolumeFraction[ip_water],
+ m_phaseOrder,
+ phaseVolFraction[ip_water],
+ dPhaseCapPres_dPhaseVolFrac[ip_water][ip_water] );
+ phaseVolFraction[ip_gas] = 1.0 - phaseVolFraction[ip_water];
+ }
+
+
+ // compute first gas-oil capillary pressure as a function of gas-phase vol fraction
+
+
+ // if( ip_gas >= 0 )
+ // {
+ // real64 const volFracScaled_eps = (eps - m_phaseMinVolumeFraction[ip_gas]) * volFracScaleInv;
+ // real64 const exponentInv = m_phaseCapPressureExponentInv[ip_gas];
+ // real64 const entryPressure = -m_phaseEntryPressure[ip_gas]; // for gas capillary pressure, take the opposite of the
+ // // BC function
+
+ // real64 const wettingVolFracScaled_eps = 1-volFracScaled_eps;
+ // real64 const dWettingVolFracScaled_dVolFrac = -volFracScaleInv;
+
+ // real64 maxCapPres_eps = 0.0;
+ // real64 max_dpc_eps = 0.0;
+
+ // evaluateBrooksCoreyFunction( wettingVolFracScaled_eps,
+ // dWettingVolFracScaled_dVolFrac,
+ // exponentInv,
+ // entryPressure,
+ // eps,
+ // maxCapPres_eps,
+ // max_dpc_eps );
+
+ // evaluateBrooksCoreyFunctionInv( phaseCapPres[ip_gas],
+ // ip_gas,
+ // volFracScaleInv,
+ // exponentInv,
+ // entryPressure,
+ // maxCapPres_eps,
+ // m_phaseMinVolumeFraction[ip_gas],
+ // m_phaseOrder,
+ // phaseVolFraction[ip_gas],
+ // dPhaseCapPres_dPhaseVolFrac[ip_gas][ip_gas] );
+ // phaseVolFraction[ip_water] = 1.0 - phaseVolFraction[ip_gas];
+ // }
+}
+
GEOS_HOST_DEVICE
inline void
BrooksCoreyCapillaryPressureUpdate::
@@ -222,6 +342,49 @@ BrooksCoreyCapillaryPressureUpdate::
}
+GEOS_HOST_DEVICE
+inline void
+BrooksCoreyCapillaryPressureUpdate::
+ evaluateBrooksCoreyFunctionInv( real64 const phaseCapPressure,
+ int const ip,
+ real64 const volFracScaleInv,
+ real64 const exponentInv,
+ real64 const entryPressure,
+ real64 const maxCapPres_eps,
+ real64 const phaseMinVolumeFraction,
+ arrayView1d< integer const > const phaseOrder,
+ real64 & phaseVolFraction,
+ real64 & dPhaseCapPressure_dVolFrac )
+{
+
+
+ phaseVolFraction = 0.0;
+ real64 value = 0.0;
+ dPhaseCapPressure_dVolFrac = 0.0;
+ integer const ip_oil = phaseOrder[CapillaryPressureBase::PhaseType::OIL];
+
+ real64 const dScaledWettingPhaseVolFrac_dVolFrac = (ip == ip_oil)
+ ? -volFracScaleInv : volFracScaleInv;
+
+ if( phaseCapPressure <= maxCapPres_eps && phaseCapPressure >= entryPressure )
+ {
+ // intermediate value
+ real64 const val = pow( entryPressure, exponentInv ) / pow( phaseCapPressure, exponentInv + 1 );
+
+ value = (phaseCapPressure * val) * volFracScaleInv + phaseMinVolumeFraction; // entryPressure * (S_w)^( - 1 / exponentInv )
+ dPhaseCapPressure_dVolFrac = -dScaledWettingPhaseVolFrac_dVolFrac * val * exponentInv;
+ phaseVolFraction = (ip == ip_oil) ? 1.0 - value : value;
+ }
+ else // enforce a constant and bounded capillary pressure
+ {
+ real64 const val = (phaseCapPressure > maxCapPres_eps)
+ ? pow( entryPressure, exponentInv ) / pow( maxCapPres_eps, exponentInv ) : 1.0;
+ value = val * volFracScaleInv + phaseMinVolumeFraction;
+ phaseVolFraction = (ip == ip_oil) ? 1.0 - value : value;
+ }
+
+}
+
} // namespace constitutive
diff --git a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.cpp b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.cpp
index beb2c0ce246..02ee783de6c 100644
--- a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.cpp
+++ b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.cpp
@@ -52,6 +52,7 @@ CapillaryPressureBase::CapillaryPressureBase( string const & name,
registerField< fields::cappres::phaseCapPressure >( &m_phaseCapPressure );
registerField< fields::cappres::dPhaseCapPressure_dPhaseVolFraction >( &m_dPhaseCapPressure_dPhaseVolFrac );
+ registerField< fields::cappres::phaseTrappedVolFraction >( &m_phaseTrappedVolFrac );
}
void CapillaryPressureBase::postInputInitialization()
@@ -93,7 +94,9 @@ void CapillaryPressureBase::postInputInitialization()
void CapillaryPressureBase::allocateConstitutiveData( Group & parent, localIndex const numPts )
{
integer const NP = numFluidPhases();
-
+ //phase trapped for stats
+ m_phaseTrappedVolFrac.resize( 0, numPts, NP );
+ m_phaseTrappedVolFrac.zero();
m_phaseCapPressure.resize( 0, numPts, NP );
m_dPhaseCapPressure_dPhaseVolFrac.resize( 0, numPts, NP, NP );
@@ -102,10 +105,20 @@ void CapillaryPressureBase::allocateConstitutiveData( Group & parent, localIndex
void CapillaryPressureBase::setLabels()
{
+ getField< fields::cappres::phaseTrappedVolFraction >().
+ setDimLabels( 2, m_phaseNames );
getField< fields::cappres::phaseCapPressure >().
setDimLabels( 2, m_phaseNames );
}
+void CapillaryPressureBase::resizeFields( localIndex const size, localIndex const numPts )
+{
+ integer const NP = numFluidPhases();
+ m_phaseTrappedVolFrac.resize( size, numPts, NP );
+ m_phaseCapPressure.resize( size, numPts, NP );
+ m_dPhaseCapPressure_dPhaseVolFrac.resize( size, numPts, NP, NP );
+}
+
} // namespace constitutive
} // namespace geos
diff --git a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.hpp b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.hpp
index b0617841488..64598762aff 100644
--- a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.hpp
+++ b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureBase.hpp
@@ -60,16 +60,19 @@ class CapillaryPressureBaseUpdate
CapillaryPressureBaseUpdate( arrayView1d< integer const > const & phaseTypes,
arrayView1d< integer const > const & phaseOrder,
+ arrayView3d< real64, cappres::USD_CAPPRES > const & phaseTrapped,
arrayView3d< real64, cappres::USD_CAPPRES > const & phaseCapPressure,
arrayView4d< real64, cappres::USD_CAPPRES_DS > const & dPhaseCapPressure_dPhaseVolFrac )
: m_phaseTypes( phaseTypes ),
m_phaseOrder( phaseOrder ),
+ m_phaseTrappedVolFrac( phaseTrapped ),
m_phaseCapPressure( phaseCapPressure ),
m_dPhaseCapPressure_dPhaseVolFrac( dPhaseCapPressure_dPhaseVolFrac )
{}
arrayView1d< integer const > m_phaseTypes;
arrayView1d< integer const > m_phaseOrder;
+ arrayView3d< real64, cappres::USD_CAPPRES > m_phaseTrappedVolFrac;
arrayView3d< real64, cappres::USD_CAPPRES > m_phaseCapPressure;
arrayView4d< real64, cappres::USD_CAPPRES_DS > m_dPhaseCapPressure_dPhaseVolFrac;
@@ -130,6 +133,14 @@ class CapillaryPressureBase : public ConstitutiveBase
arrayView3d< real64 const > const & convergedPermeability ) const
{ GEOS_UNUSED_VAR( convergedPorosity, convergedPermeability ); }
+
+ /**
+ * @brief Save converged phase volume fraction at the end of a time step (needed for hysteresis)
+ * @param[in] phaseVolFraction an array containing the phase volume fractions at the end of a converged time step
+ */
+ virtual void saveConvergedPhaseVolFractionState( arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFraction ) const
+ { GEOS_UNUSED_VAR( phaseVolFraction ); }
+
/*
* @brief Getter for the number of fluid phases
* @return the number of fluid phases
@@ -182,9 +193,17 @@ class CapillaryPressureBase : public ConstitutiveBase
void setLabels();
protected:
+/**
+ * @brief Function called internally to resize member arrays
+ * @param size primary dimension (e.g. number of cells)
+ * @param numPts secondary dimension (e.g. number of gauss points per cell)
+ */
+ virtual void resizeFields( localIndex const size, localIndex const numPts );
virtual void postInputInitialization() override;
+ std::tuple< integer, integer > phaseIndex( const arrayView1d< const integer > & phaseOrder );
+
// phase names read from input
string_array m_phaseNames;
@@ -198,8 +217,45 @@ class CapillaryPressureBase : public ConstitutiveBase
// output quantities
array3d< real64, cappres::LAYOUT_CAPPRES > m_phaseCapPressure;
array4d< real64, cappres::LAYOUT_CAPPRES_DS > m_dPhaseCapPressure_dPhaseVolFrac;
+
+ // trapped fraction
+ array3d< real64, cappres::LAYOUT_CAPPRES > m_phaseTrappedVolFrac;
};
+inline std::tuple< integer, integer > CapillaryPressureBase::phaseIndex( arrayView1d< integer const > const & phaseOrder )
+{
+ using PT = PhaseType;
+ integer const ipWater = phaseOrder[PT::WATER];
+ integer const ipOil = phaseOrder[PT::OIL];
+ integer const ipGas = phaseOrder[PT::GAS];
+
+ integer ipWetting = -1, ipNonWetting = -1;
+
+ if( ipWater >= 0 && ipOil >= 0 && ipGas >= 0 )
+ {
+ ipWetting = ipWater;
+ ipNonWetting = ipGas;
+ }
+ else if( ipWater < 0 )
+ {
+ ipWetting = ipOil;
+ ipNonWetting = ipGas;
+ }
+ else if( ipOil < 0 )
+ {
+ ipWetting = ipWater;
+ ipNonWetting = ipGas;
+ }
+ else if( ipGas < 0 )
+ {
+ ipWetting = ipWater;
+ ipNonWetting = ipOil;
+ }
+
+ //maybe a bit too pythonic
+ return std::make_tuple( ipWetting, ipNonWetting );
+}
+
} // namespace constitutive
} // namespace geos
diff --git a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureFields.hpp b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureFields.hpp
index 653b7faeda8..402eaff93d4 100644
--- a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureFields.hpp
+++ b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureFields.hpp
@@ -32,9 +32,21 @@ namespace fields
namespace cappres
{
+using array2dLayoutPhase = array2d< real64, compflow::LAYOUT_PHASE >;
using array3dLayoutCapPressure = array3d< real64, constitutive::cappres::LAYOUT_CAPPRES >;
using array4dLayoutCapPressure_dS = array4d< real64, constitutive::cappres::LAYOUT_CAPPRES_DS >;
+
+
+enum ModeIndexType : integer
+{
+ DRAINAGE = 0, //to be used in array of Kernels
+ IMBIBITION = 1,
+ DRAINAGE_TO_IMBIBITION = 2,
+ IMBIBITION_TO_DRAINAGE = 3,
+ IMBIBITION_TO_DRAINAGE_FROM_SCANNING = 4
+};
+
DECLARE_FIELD( phaseCapPressure,
"phaseCapPressure",
array3dLayoutCapPressure,
@@ -59,6 +71,48 @@ DECLARE_FIELD( jFuncMultiplier,
WRITE_AND_READ,
"Multiplier for the Leverett J-function" );
+DECLARE_FIELD( phaseTrappedVolFraction,
+ "phaseTrappedVolumeFraction",
+ array3dLayoutCapPressure,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Phase Trapped Volume Fraction" );
+
+DECLARE_FIELD( mode,
+ "Hysteresis Mode",
+ array1d< integer >,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Hysteresis mode" );
+
+
+DECLARE_FIELD( phaseMaxHistoricalVolFraction,
+ "phaseMaxHistoricalVolFraction",
+ array2dLayoutPhase,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Phase max historical phase volume fraction" );
+
+DECLARE_FIELD( phaseMinHistoricalVolFraction,
+ "phaseMinHistoricalVolFraction",
+ array2dLayoutPhase,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Phase min historical phase volume fraction" );
+
+DECLARE_FIELD( phaseMode2PeakVolFraction,
+ "phaseMode2PeakVolFraction",
+ array2dLayoutPhase,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Peak saturation reached during Mode 2 (DRAINAGE_TO_IMBIBITION)" );
+
+
}
}
diff --git a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureSelector.hpp b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureSelector.hpp
index b164f55aa16..a8382183ba4 100644
--- a/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureSelector.hpp
+++ b/src/coreComponents/constitutive/capillaryPressure/CapillaryPressureSelector.hpp
@@ -24,6 +24,7 @@
#include "constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.hpp"
#include "constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp"
#include "constitutive/capillaryPressure/TableCapillaryPressure.hpp"
+#include "constitutive/capillaryPressure/TableCapillaryPressureHysteresis.hpp"
#include "constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.hpp"
namespace geos
@@ -39,6 +40,7 @@ void constitutiveUpdatePassThru( CapillaryPressureBase const & capPres,
ConstitutivePassThruHandler< BrooksCoreyCapillaryPressure,
JFunctionCapillaryPressure,
TableCapillaryPressure,
+ TableCapillaryPressureHysteresis,
VanGenuchtenCapillaryPressure >::execute( capPres, std::forward< LAMBDA >( lambda ) );
}
@@ -49,6 +51,7 @@ void constitutiveUpdatePassThru( CapillaryPressureBase & capPres,
ConstitutivePassThruHandler< BrooksCoreyCapillaryPressure,
JFunctionCapillaryPressure,
TableCapillaryPressure,
+ TableCapillaryPressureHysteresis,
VanGenuchtenCapillaryPressure >::execute( capPres, std::forward< LAMBDA >( lambda ) );
}
diff --git a/src/coreComponents/constitutive/capillaryPressure/InverseCapillaryPressure.cpp b/src/coreComponents/constitutive/capillaryPressure/InverseCapillaryPressure.cpp
index 534037c55f4..0156d06ab67 100644
--- a/src/coreComponents/constitutive/capillaryPressure/InverseCapillaryPressure.cpp
+++ b/src/coreComponents/constitutive/capillaryPressure/InverseCapillaryPressure.cpp
@@ -20,6 +20,7 @@
#include "InverseCapillaryPressure.hpp"
#include "constitutive/capillaryPressure/BrooksCoreyCapillaryPressure.hpp"
#include "constitutive/capillaryPressure/TableCapillaryPressure.hpp"
+#include "constitutive/capillaryPressure/TableCapillaryPressureHysteresis.hpp"
#include "constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.hpp"
#include "constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp"
@@ -317,6 +318,7 @@ void InverseCapillaryPressure< CAP_PRESSURE >::calculateJFunctionIndex( integer
template class InverseCapillaryPressure< BrooksCoreyCapillaryPressure >;
template class InverseCapillaryPressure< TableCapillaryPressure >;
+template class InverseCapillaryPressure< TableCapillaryPressureHysteresis >;
template class InverseCapillaryPressure< JFunctionCapillaryPressure >;
template class InverseCapillaryPressure< VanGenuchtenCapillaryPressure >;
template class InverseCapillaryPressure< NoOpCapillaryPressure >;
diff --git a/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.cpp b/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.cpp
index d0eaa9ce36b..86fe82e6097 100644
--- a/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.cpp
+++ b/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.cpp
@@ -119,6 +119,14 @@ JFunctionCapillaryPressure::JFunctionCapillaryPressure( std::string const & name
.setInputFlag( InputFlags::FALSE );
registerField< fields::cappres::jFuncMultiplier >( &m_jFuncMultiplier );
+
+ registerWrapper( viewKeyStruct::jFunctionWrappersString(), &m_jFuncKernelWrappers ).
+ setSizedFromParent( 0 ).
+ setRestartFlags( RestartFlags::NO_WRITE );
+
+ registerWrapper( viewKeyStruct::inverseJFunctionWrappersString(), &m_inverseJFuncKernelWrappers ).
+ setSizedFromParent( 0 ).
+ setRestartFlags( RestartFlags::NO_WRITE );
}
void JFunctionCapillaryPressure::postInputInitialization()
@@ -181,6 +189,7 @@ void JFunctionCapillaryPressure::initializePreSubGroups()
? true // pc on the gas phase, function must be increasing
: false; // pc on the water phase, function must be decreasing
TableCapillaryPressureHelpers::validateCapillaryPressureTable( jFuncTable, getFullName(), jFuncMustBeIncreasing );
+
}
else if( numPhases == 3 )
{
@@ -197,6 +206,7 @@ void JFunctionCapillaryPressure::initializePreSubGroups()
InputError, getDataContext() );
TableFunction const & jFuncTableNWI = functionManager.getGroup< TableFunction >( m_nonWettingIntermediateJFuncTableName );
TableCapillaryPressureHelpers::validateCapillaryPressureTable( jFuncTableNWI, getFullName(), true );
+
}
}
@@ -292,11 +302,48 @@ void JFunctionCapillaryPressure::createAllTableKernelWrappers()
// we want to make sure that the wrappers are always up-to-date, so we recreate them everytime
m_jFuncKernelWrappers.clear();
+ m_inverseJFuncKernelWrappers.clear();
+
if( numPhases == 2 )
{
+
TableFunction const & jFuncTable = functionManager.getGroup< TableFunction >( m_wettingNonWettingJFuncTableName );
m_jFuncKernelWrappers.emplace_back( jFuncTable.createKernelWrapper() );
+ auto const & satArrayView = jFuncTable.getCoordinates()[0];
+ auto const & jArrayView = jFuncTable.getValues();
+
+ std::vector< real64 > satVec( satArrayView.size() );
+ std::vector< real64 > jVec( jArrayView.size() );
+
+ std::copy( satArrayView.begin(), satArrayView.end(), satVec.begin() );
+ std::copy( jArrayView.begin(), jArrayView.end(), jVec.begin() );
+
+ // Reverse both arrays (if original J is decreasing in S)
+ std::reverse( jVec.begin(), jVec.end() );
+ std::reverse( satVec.begin(), satVec.end() );
+
+
+ auto inverseTable = std::make_shared< TableFunction >( "inverseJFunc", this );
+
+ real64_array invJVec( jVec.size() );
+ real64_array invSatVec( satVec.size() );
+ std::copy( jVec.begin(), jVec.end(), invJVec.data() );
+ std::copy( satVec.begin(), satVec.end(), invSatVec.data() );
+
+ array1d< real64_array > coordinates;
+ coordinates.emplace_back( std::move( invJVec ) );
+
+
+ std::vector< units::Unit > dimUnits = { units::Unknown }; // or actual unit if available
+
+ inverseTable->setTableCoordinates( coordinates, dimUnits );
+ inverseTable->setTableValues( std::move( invSatVec ), units::Unknown );
+ inverseTable->setInterpolationMethod( TableFunction::InterpolationType::Linear );
+
+ m_inverseJFuncKernelWrappers.emplace_back( inverseTable->createKernelWrapper() );
+ m_inverseTables.emplace_back( std::move( inverseTable ) );
+
// Populate the end-points from the tables
TableCapillaryPressureHelpers::populateMinPhaseVolumeFraction( m_phaseOrder.toSliceConst(), jFuncTable, m_phaseMinVolumeFraction );
}
@@ -305,8 +352,10 @@ void JFunctionCapillaryPressure::createAllTableKernelWrappers()
// the assumption used everywhere in this class is that the WI information comes before the NWI information
TableFunction const & jFuncTableWI = functionManager.getGroup< TableFunction >( m_wettingIntermediateJFuncTableName );
m_jFuncKernelWrappers.emplace_back( jFuncTableWI.createKernelWrapper() );
+ m_inverseJFuncKernelWrappers.emplace_back( jFuncTableWI.createKernelWrapper() );
TableFunction const & jFuncTableNWI = functionManager.getGroup< TableFunction >( m_nonWettingIntermediateJFuncTableName );
m_jFuncKernelWrappers.emplace_back( jFuncTableNWI.createKernelWrapper() );
+ m_inverseJFuncKernelWrappers.emplace_back( jFuncTableNWI.createKernelWrapper() );
// Populate the end-points from the tables
TableCapillaryPressureHelpers::populateMinPhaseVolumeFraction( m_phaseOrder.toSliceConst(), jFuncTableWI, jFuncTableNWI, m_phaseMinVolumeFraction );
@@ -315,16 +364,20 @@ void JFunctionCapillaryPressure::createAllTableKernelWrappers()
JFunctionCapillaryPressure::KernelWrapper::
KernelWrapper( arrayView1d< TableFunction::KernelWrapper const > const & jFuncKernelWrappers,
+ arrayView1d< TableFunction::KernelWrapper const > const & inverseJFuncKernelWrappers,
arrayView2d< real64 const > const & jFuncMultiplier,
arrayView1d< integer const > const & phaseTypes,
arrayView1d< integer const > const & phaseOrder,
+ arrayView3d< real64, cappres::USD_CAPPRES > const & phaseTrapped,
arrayView3d< real64, cappres::USD_CAPPRES > const & phaseCapPres,
arrayView4d< real64, cappres::USD_CAPPRES_DS > const & dPhaseCapPres_dPhaseVolFrac )
: CapillaryPressureBaseUpdate( phaseTypes,
phaseOrder,
+ phaseTrapped,
phaseCapPres,
dPhaseCapPres_dPhaseVolFrac ),
m_jFuncKernelWrappers( jFuncKernelWrappers ),
+ m_inverseJFuncKernelWrappers( inverseJFuncKernelWrappers ),
m_jFuncMultiplier( jFuncMultiplier )
{}
@@ -333,9 +386,11 @@ JFunctionCapillaryPressure::createKernelWrapper()
{
createAllTableKernelWrappers();
return KernelWrapper( m_jFuncKernelWrappers,
+ m_inverseJFuncKernelWrappers,
m_jFuncMultiplier,
m_phaseTypes,
m_phaseOrder,
+ m_phaseTrappedVolFrac,
m_phaseCapPressure,
m_dPhaseCapPressure_dPhaseVolFrac );
}
diff --git a/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp b/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp
index 4e42189d92e..29e7692bd95 100644
--- a/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp
+++ b/src/coreComponents/constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp
@@ -65,9 +65,11 @@ class JFunctionCapillaryPressure : public CapillaryPressureBase
public:
KernelWrapper( arrayView1d< TableFunction::KernelWrapper const > const & jFuncKernelWrappers,
+ arrayView1d< TableFunction::KernelWrapper const > const & inverseJFuncKernelWrappers,
arrayView2d< real64 const > const & jFuncMultiplier,
arrayView1d< integer const > const & phaseTypes,
arrayView1d< integer const > const & phaseOrder,
+ arrayView3d< real64, cappres::USD_CAPPRES > const & phaseTrapped,
arrayView3d< real64, cappres::USD_CAPPRES > const & phaseCapPres,
arrayView4d< real64, cappres::USD_CAPPRES_DS > const & dPhaseCapPres_dPhaseVolFrac );
@@ -77,6 +79,13 @@ class JFunctionCapillaryPressure : public CapillaryPressureBase
arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const;
+ GEOS_HOST_DEVICE
+ void computeInv( arraySlice1d< real64, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const > const & jFuncMultiplier,
+ arraySlice1d< real64 const, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const;
+
+
GEOS_HOST_DEVICE
virtual void update( localIndex const k,
localIndex const q,
@@ -87,6 +96,7 @@ class JFunctionCapillaryPressure : public CapillaryPressureBase
/// Array of kernel wrappers for the J-function
/// Is of size 1 for two-phase flow, and of size 2 for three-phase flow
arrayView1d< TableFunction::KernelWrapper const > const m_jFuncKernelWrappers;
+ arrayView1d< TableFunction::KernelWrapper const > const m_inverseJFuncKernelWrappers;
/// Array of cell-wise J-function multipliers
/// The second dimension is of size 1 for two-phase flow, and of size 2 for three-phase flow
@@ -112,6 +122,8 @@ class JFunctionCapillaryPressure : public CapillaryPressureBase
static constexpr char const * porosityExponentString() { return "porosityExponent"; }
static constexpr char const * permeabilityExponentString() { return "permeabilityExponent"; }
static constexpr char const * permeabilityDirectionString() { return "permeabilityDirection"; }
+ static constexpr char const * jFunctionWrappersString() { return "jFunctionWrappers"; }
+ static constexpr char const * inverseJFunctionWrappersString() { return "inverseJFunctionWrappers"; }
};
/**
@@ -168,6 +180,9 @@ class JFunctionCapillaryPressure : public CapillaryPressureBase
/// J-function kernel wrapper for the first pair (wetting-intermediate if NP=3, wetting-non-wetting otherwise)
array1d< TableFunction::KernelWrapper > m_jFuncKernelWrappers;
+ array1d< TableFunction::KernelWrapper > m_inverseJFuncKernelWrappers;
+
+ std::vector< std::shared_ptr< TableFunction > > m_inverseTables;
};
@@ -242,6 +257,42 @@ JFunctionCapillaryPressure::KernelWrapper::
}
}
+GEOS_HOST_DEVICE
+inline void
+JFunctionCapillaryPressure::KernelWrapper::
+ computeInv( arraySlice1d< real64, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const > const & jFuncMultiplier,
+ arraySlice1d< real64 const, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const
+{
+ LvArray::forValuesInSlice( dPhaseCapPres_dPhaseVolFrac, []( real64 & val ){ val = 0.0; } );
+
+ using PT = CapillaryPressureBase::PhaseType;
+ integer const ipWater = m_phaseOrder[PT::WATER];
+ integer const ipOil = m_phaseOrder[PT::OIL];
+ integer const ipGas = m_phaseOrder[PT::GAS];
+
+ GEOS_UNUSED_VAR( ipOil );
+ // apply multiplier
+ real64 capPresWater_J = phaseCapPres[ipWater] / jFuncMultiplier[0];
+ // std::cout << GEOS_FMT( " JM_2 = ( {:4.2e} )", jFuncMultiplier[0] );
+ array1d< real64 > input( 1 );
+ input[0] = capPresWater_J;
+ // std::cout << GEOS_FMT( " J_int2 = ( {:4.2e} )", input[0] );
+ // std::cout << GEOS_FMT( " Pc_int2 = ( {:4.2e} )", phaseCapPres[ipWater] );
+ auto inputSlice = input.toSliceConst();
+
+
+
+ phaseVolFraction[ipWater] =
+ m_inverseJFuncKernelWrappers[0].compute( inputSlice,
+ &(dPhaseCapPres_dPhaseVolFrac)[ipWater][ipWater] );
+ dPhaseCapPres_dPhaseVolFrac[ipWater][ipWater] /= jFuncMultiplier[0];
+ // std::cout << GEOS_FMT( " S_int2 = ( {:4.2e} )", phaseVolFraction[ipWater] );
+ // std::cout << GEOS_FMT( " dS/dP = ( {:4.2e} )", dPhaseCapPres_dPhaseVolFrac[ipWater][ipWater] );
+ phaseVolFraction[ipGas] = 1.0 - phaseVolFraction[ipWater];
+}
+
GEOS_HOST_DEVICE
inline void
JFunctionCapillaryPressure::KernelWrapper::
diff --git a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.cpp b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.cpp
index f346fff4222..9059ebc676c 100644
--- a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.cpp
+++ b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.cpp
@@ -69,6 +69,10 @@ TableCapillaryPressure::TableCapillaryPressure( std::string const & name,
registerWrapper( viewKeyStruct::capPresWrappersString(), &m_capPresKernelWrappers ).
setSizedFromParent( 0 ).
setRestartFlags( RestartFlags::NO_WRITE );
+
+ registerWrapper( viewKeyStruct::inverseCapPresWrappersString(), &m_inverseCapPresWrappers ).
+ setSizedFromParent( 0 ).
+ setRestartFlags( RestartFlags::NO_WRITE );
}
void TableCapillaryPressure::postInputInitialization()
@@ -77,7 +81,8 @@ void TableCapillaryPressure::postInputInitialization()
integer const numPhases = m_phaseNames.size();
GEOS_THROW_IF( numPhases != 2 && numPhases != 3,
- "the expected number of fluid phases is either two, or three",
+ GEOS_FMT( "{}: the expected number of fluid phases is either two, or three",
+ getFullName() ),
InputError, getDataContext() );
// Populate the minimum phase volumes
@@ -86,16 +91,18 @@ void TableCapillaryPressure::postInputInitialization()
if( numPhases == 2 )
{
GEOS_THROW_IF( m_wettingNonWettingCapPresTableName.empty(),
- GEOS_FMT( "for a two-phase flow simulation, we must use {} to specify the capillary pressure table for the pair (wetting phase, non-wetting phase)",
+ GEOS_FMT( "{}: for a two-phase flow simulation, we must use {} to specify the capillary pressure table for the pair (wetting phase, non-wetting phase)",
+ getFullName(),
viewKeyStruct::wettingNonWettingCapPresTableNameString() ),
InputError, getDataContext() );
}
else if( numPhases == 3 )
{
GEOS_THROW_IF( m_wettingIntermediateCapPresTableName.empty() || m_nonWettingIntermediateCapPresTableName.empty(),
- GEOS_FMT( "for a three-phase flow simulation, we must use {} to specify the capillary pressure table "
+ GEOS_FMT( "{}: for a three-phase flow simulation, we must use {} to specify the capillary pressure table "
"for the pair (wetting phase, intermediate phase), and {} to specify the capillary pressure table "
"for the pair (non-wetting phase, intermediate phase)",
+ getFullName(),
viewKeyStruct::wettingIntermediateCapPresTableNameString(),
viewKeyStruct::nonWettingIntermediateCapPresTableNameString() ),
InputError, getDataContext() );
@@ -112,9 +119,10 @@ void TableCapillaryPressure::initializePreSubGroups()
if( numPhases == 2 )
{
GEOS_THROW_IF( !functionManager.hasGroup( m_wettingNonWettingCapPresTableName ),
- GEOS_FMT( "the table function named {} could not be found",
+ GEOS_FMT( "{}: the table function named {} could not be found",
+ getFullName(),
m_wettingNonWettingCapPresTableName ),
- InputError, getDataContext() );
+ InputError );
TableFunction const & capPresTable = functionManager.getGroup< TableFunction >( m_wettingNonWettingCapPresTableName );
bool const capPresMustBeIncreasing = ( m_phaseOrder[PhaseType::WATER] < 0 )
? true // pc on the gas phase, function must be increasing
@@ -124,14 +132,16 @@ void TableCapillaryPressure::initializePreSubGroups()
else if( numPhases == 3 )
{
GEOS_THROW_IF( !functionManager.hasGroup( m_wettingIntermediateCapPresTableName ),
- GEOS_FMT( "the table function named {} could not be found",
+ GEOS_FMT( "{}: the table function named {} could not be found",
+ getFullName(),
m_wettingIntermediateCapPresTableName ),
InputError, getDataContext() );
TableFunction const & capPresTableWI = functionManager.getGroup< TableFunction >( m_wettingIntermediateCapPresTableName );
TableCapillaryPressureHelpers::validateCapillaryPressureTable( capPresTableWI, getFullName(), false );
GEOS_THROW_IF( !functionManager.hasGroup( m_nonWettingIntermediateCapPresTableName ),
- GEOS_FMT( "the table function named {} could not be found",
+ GEOS_FMT( "{}: the table function named {} could not be found",
+ getFullName(),
m_nonWettingIntermediateCapPresTableName ),
InputError, getDataContext() );
TableFunction const & capPresTableNWI = functionManager.getGroup< TableFunction >( m_nonWettingIntermediateCapPresTableName );
@@ -148,11 +158,47 @@ void TableCapillaryPressure::createAllTableKernelWrappers()
// we want to make sure that the wrappers are always up-to-date, so we recreate them everytime
m_capPresKernelWrappers.clear();
+ m_inverseCapPresWrappers.clear();
+ m_inverseTables.clear();
+
if( numPhases == 2 )
{
TableFunction const & capPresTable = functionManager.getGroup< TableFunction >( m_wettingNonWettingCapPresTableName );
m_capPresKernelWrappers.emplace_back( capPresTable.createKernelWrapper() );
+ auto const & satArrayView = capPresTable.getCoordinates()[0];
+ auto const & capPresArrayView = capPresTable.getValues();
+
+ std::vector< real64 > satVec( satArrayView.size() );
+ std::vector< real64 > pcVec( capPresArrayView.size() );
+
+ std::copy( satArrayView.begin(), satArrayView.end(), satVec.begin() );
+ std::copy( capPresArrayView.begin(), capPresArrayView.end(), pcVec.begin() );
+
+ // Reverse both arrays (if original J is decreasing in S)
+ std::reverse( pcVec.begin(), pcVec.end() );
+ std::reverse( satVec.begin(), satVec.end() );
+
+ auto inverseTable = std::make_shared< TableFunction >( "inverseCapPres", this );
+
+ real64_array invPcVec( pcVec.size() );
+ real64_array invSatVec( satVec.size() );
+ std::copy( pcVec.begin(), pcVec.end(), invPcVec.data() );
+ std::copy( satVec.begin(), satVec.end(), invSatVec.data() );
+
+ array1d< real64_array > coordinates;
+ coordinates.emplace_back( std::move( invPcVec ) );
+
+
+ std::vector< units::Unit > dimUnits = { units::Unknown }; // or actual unit if available
+
+ inverseTable->setTableCoordinates( coordinates, dimUnits );
+ inverseTable->setTableValues( std::move( invSatVec ), units::Unknown );
+ inverseTable->setInterpolationMethod( TableFunction::InterpolationType::Linear );
+
+ m_inverseCapPresWrappers.emplace_back( inverseTable->createKernelWrapper() );
+ m_inverseTables.emplace_back( std::move( inverseTable ) );
+
// Populate the end-points from the tables
TableCapillaryPressureHelpers::populateMinPhaseVolumeFraction( m_phaseOrder.toSliceConst(), capPresTable, m_phaseMinVolumeFraction );
}
@@ -160,8 +206,10 @@ void TableCapillaryPressure::createAllTableKernelWrappers()
{
TableFunction const & capPresTableWI = functionManager.getGroup< TableFunction >( m_wettingIntermediateCapPresTableName );
m_capPresKernelWrappers.emplace_back( capPresTableWI.createKernelWrapper() );
+ m_inverseCapPresWrappers.emplace_back( capPresTableWI.createKernelWrapper() );
TableFunction const & capPresTableNWI = functionManager.getGroup< TableFunction >( m_nonWettingIntermediateCapPresTableName );
m_capPresKernelWrappers.emplace_back( capPresTableNWI.createKernelWrapper() );
+ m_inverseCapPresWrappers.emplace_back( capPresTableNWI.createKernelWrapper() );
// Populate the end-points from the tables
TableCapillaryPressureHelpers::populateMinPhaseVolumeFraction( m_phaseOrder.toSliceConst(), capPresTableWI, capPresTableNWI, m_phaseMinVolumeFraction );
@@ -171,15 +219,19 @@ void TableCapillaryPressure::createAllTableKernelWrappers()
TableCapillaryPressure::KernelWrapper::
KernelWrapper( arrayView1d< TableFunction::KernelWrapper const > const & capPresKernelWrappers,
+ arrayView1d< TableFunction::KernelWrapper const > const & inverseCapPresWrappers,
arrayView1d< integer const > const & phaseTypes,
arrayView1d< integer const > const & phaseOrder,
+ arrayView3d< real64, cappres::USD_CAPPRES > const & phaseTrapped,
arrayView3d< real64, cappres::USD_CAPPRES > const & phaseCapPres,
arrayView4d< real64, cappres::USD_CAPPRES_DS > const & dPhaseCapPres_dPhaseVolFrac )
: CapillaryPressureBaseUpdate( phaseTypes,
phaseOrder,
+ phaseTrapped,
phaseCapPres,
dPhaseCapPres_dPhaseVolFrac ),
- m_capPresKernelWrappers( capPresKernelWrappers )
+ m_capPresKernelWrappers( capPresKernelWrappers ),
+ m_inverseCapPresWrappers( inverseCapPresWrappers )
{}
TableCapillaryPressure::KernelWrapper
@@ -187,8 +239,10 @@ TableCapillaryPressure::createKernelWrapper()
{
createAllTableKernelWrappers();
return KernelWrapper( m_capPresKernelWrappers,
+ m_inverseCapPresWrappers,
m_phaseTypes,
m_phaseOrder,
+ m_phaseTrappedVolFrac,
m_phaseCapPressure,
m_dPhaseCapPressure_dPhaseVolFrac );
}
diff --git a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.hpp b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.hpp
index 739b9993083..f7b661a6090 100644
--- a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.hpp
+++ b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressure.hpp
@@ -55,8 +55,10 @@ class TableCapillaryPressure : public CapillaryPressureBase
public:
KernelWrapper( arrayView1d< TableFunction::KernelWrapper const > const & capPresKernelWrappers,
+ arrayView1d< TableFunction::KernelWrapper const > const & inverseCapPresWrappers,
arrayView1d< integer const > const & phaseTypes,
arrayView1d< integer const > const & phaseOrder,
+ arrayView3d< real64, cappres::USD_CAPPRES > const & phaseTrapped,
arrayView3d< real64, cappres::USD_CAPPRES > const & phaseCapPres,
arrayView4d< real64, cappres::USD_CAPPRES_DS > const & dPhaseCapPres_dPhaseVolFrac );
@@ -65,6 +67,12 @@ class TableCapillaryPressure : public CapillaryPressureBase
arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const;
+ GEOS_HOST_DEVICE
+ void computeInv( arraySlice1d< real64, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const;
+
+
GEOS_HOST_DEVICE
virtual void update( localIndex const k,
localIndex const q,
@@ -75,6 +83,7 @@ class TableCapillaryPressure : public CapillaryPressureBase
/// Array of kernel wrappers for the capillary pressures
/// Is of size 1 for two-phase flow, and of size 2 for three-phase flow
arrayView1d< TableFunction::KernelWrapper const > const m_capPresKernelWrappers;
+ arrayView1d< TableFunction::KernelWrapper const > const m_inverseCapPresWrappers;
};
@@ -91,6 +100,7 @@ class TableCapillaryPressure : public CapillaryPressureBase
static constexpr char const * wettingIntermediateCapPresTableNameString() { return "wettingIntermediateCapPressureTableName"; }
static constexpr char const * nonWettingIntermediateCapPresTableNameString() { return "nonWettingIntermediateCapPressureTableName"; }
static constexpr char const * capPresWrappersString() { return "capPresWrappers"; }
+ static constexpr char const * inverseCapPresWrappersString() { return "inverseCapPresWrappers"; }
};
@@ -116,6 +126,9 @@ class TableCapillaryPressure : public CapillaryPressureBase
/// Capillary pressure kernel wrapper for the first pair (wetting-intermediate if NP=3, wetting-non-wetting otherwise)
array1d< TableFunction::KernelWrapper > m_capPresKernelWrappers;
+ array1d< TableFunction::KernelWrapper > m_inverseCapPresWrappers;
+
+ std::vector< std::shared_ptr< TableFunction > > m_inverseTables;
};
@@ -173,6 +186,37 @@ TableCapillaryPressure::KernelWrapper::
}
}
+GEOS_HOST_DEVICE
+inline void
+TableCapillaryPressure::KernelWrapper::
+ computeInv( arraySlice1d< real64, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const
+{
+ LvArray::forValuesInSlice( dPhaseCapPres_dPhaseVolFrac, []( real64 & val ){ val = 0.0; } );
+
+ using PT = CapillaryPressureBase::PhaseType;
+ integer const ipWater = m_phaseOrder[PT::WATER];
+ integer const ipOil = m_phaseOrder[PT::OIL];
+ integer const ipGas = m_phaseOrder[PT::GAS];
+
+ GEOS_UNUSED_VAR( ipOil );
+
+ // put capillary pressure on the wetting phase
+ real64 capPresWater = phaseCapPres[ipWater];
+ array1d< real64 > input( 1 );
+ input[0] = capPresWater;
+ auto inputSlice = input.toSliceConst();
+
+ phaseVolFraction[ipWater] =
+ m_inverseCapPresWrappers[0].compute( inputSlice,
+ &(dPhaseCapPres_dPhaseVolFrac)[ipWater][ipWater] );
+
+ phaseVolFraction[ipGas] = 1.0 - phaseVolFraction[ipWater];
+
+}
+
+
GEOS_HOST_DEVICE
inline void
TableCapillaryPressure::KernelWrapper::
diff --git a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.cpp b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.cpp
index 90dbfedc5ac..a9ffc25aaf3 100644
--- a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.cpp
+++ b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.cpp
@@ -130,17 +130,50 @@ void TableCapillaryPressureHelpers::populateMinPhaseVolumeFraction(
}
void
-TableCapillaryPressureHelpers::validateCapillaryPressureTable( geos::TableFunction const & capPresTable,
- geos::string const & fullConstitutiveName,
- bool const capPresMustBeIncreasing,
- geos::real64 & phaseMax, geos::real64 & phaseMin )
+TableCapillaryPressureHelpers::validateCapillaryPressureTable( const geos::TableFunction & capPresTable,
+ const geos::string & fullConstitutiveName,
+ const bool capPresMustBeIncreasing,
+ geos::real64 & phaseMax,
+ geos::real64 & phaseMin,
+ geos::real64 & phaseCapPresMinEndPoint,
+ geos::real64 & phaseCapPresMaxEndPoint )
{
TableCapillaryPressureHelpers::validateCapillaryPressureTable( capPresTable, fullConstitutiveName, capPresMustBeIncreasing );
ArrayOfArraysView< real64 const > coords = capPresTable.getCoordinates();
arraySlice1d< real64 const > phaseVolFrac = coords[0];
+ arrayView1d< real64 const > const capPres = capPresTable.getValues();
+
phaseMin = phaseVolFrac[0];
+ phaseCapPresMinEndPoint = capPres[0];
phaseMax = phaseVolFrac[phaseVolFrac.size()-1];
+ phaseCapPresMaxEndPoint = capPres[phaseVolFrac.size()-1];
+
+
+ if( capPresMustBeIncreasing )
+ {
+
+ for( localIndex i = 1; i < coords.sizeOfArray( 0 ); ++i )
+ {
+ if( isZero( capPres[i - 1] ) && !isZero( capPres[i] ))
+ {
+ phaseMin = phaseVolFrac[i - 1];
+ phaseCapPresMinEndPoint = capPres[i - 1];
+ }
+ }
+ }
+ else
+ {
+ for( localIndex i = coords.sizeOfArray( 0 )-2; i>0; --i )
+ {
+ if( isZero( capPres[i + 1] ) && !isZero( capPres[i] ))
+ {
+ phaseMax = phaseVolFrac[i + 1];
+ phaseCapPresMaxEndPoint = capPres[i + 1];
+ }
+ }
+
+ }
}
diff --git a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.hpp b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.hpp
index a691637002c..276d8c3eb92 100644
--- a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.hpp
+++ b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHelpers.hpp
@@ -47,7 +47,9 @@ struct TableCapillaryPressureHelpers
string const & fullConstitutiveName,
bool const capPresMustBeIncreasing,
real64 & phaseMax,
- real64 & phaseMin );
+ real64 & phaseMin,
+ real64 & phaseCapPresMinEndPoint,
+ real64 & phaseCapPresMaxEndPoint );
/**
* @brief Populates the minimum phase volume fraction for each phase from the ends of the provided tables
diff --git a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHysteresis.cpp b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHysteresis.cpp
new file mode 100644
index 00000000000..bac73e91ba1
--- /dev/null
+++ b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHysteresis.cpp
@@ -0,0 +1,4342 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University
+ * Copyright (c) 2018-2020 TotalEnergies
+ * Copyright (c) 2019- GEOSX Contributors
+ * All rights reserved
+ *
+ * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+
+
+#include "TableCapillaryPressureHysteresis.hpp"
+
+#include "constitutive/capillaryPressure/TableCapillaryPressureHelpers.hpp"
+#include "functions/FunctionManager.hpp"
+#include "constitutive/ConstitutiveManager.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+namespace constitutive
+{
+
+TableCapillaryPressureHysteresis::TableCapillaryPressureHysteresis( const std::string & name,
+ dataRepository::Group * const parent )
+ : CapillaryPressureBase( name, parent )
+{
+
+ registerWrapper( viewKeyStruct::phaseHasHysteresisString(), &m_phaseHasHysteresis ).
+ setInputFlag( InputFlags::FALSE )
+ . // will be deduced from tables
+ setSizedFromParent( 0 );
+
+ registerWrapper( viewKeyStruct::landParameterString(), &m_landParam ).
+ setInputFlag( InputFlags::FALSE ). // will be deduced from tables
+ setSizedFromParent( 0 );
+
+ //2phase
+ registerWrapper( viewKeyStruct::drainageWettingNonWettingCapPresTableNameString(),
+ &m_drainageWettingNonWettingCapPresTableName ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Name of the drainage two-phase table for capillary pressure curve. \n"
+ "If you want to use 3-phase flow please use instead " +
+ string( viewKeyStruct::drainageWettingIntermediateCapPresTableNameString()) +
+ " and " +
+ string( viewKeyStruct::drainageNonWettingIntermediateCapPresTableNameString()) +
+ "to specify the tables names" );
+ registerWrapper( viewKeyStruct::imbibitionWettingNonWettingCapPresTableNameString(),
+ &m_imbibitionWettingNonWettingCapPresTableName ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Name of the drainage two-phase table for capillary pressure curve. \n"
+ "If you want to use 3-phase flow please use instead " +
+ string( viewKeyStruct::imbibitionWettingIntermediateCapPresTableNameString()) +
+ " and " +
+ string( viewKeyStruct::imbibitionNonWettingIntermediateCapPresTableNameString()) +
+ "to specify the tables names" );
+ //3phase
+ registerWrapper( viewKeyStruct::drainageWettingIntermediateCapPresTableNameString(),
+ &m_drainageWettingIntermediateCapPresTableName ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription(
+ "Drainage wetting/intermediate (e.g. w/o) capillary pressure table name for the wetting phase.\n"
+ "To neglect hysteresis on this phase, just use the same table name for the drainage and imbibition curves" );
+ registerWrapper( viewKeyStruct::drainageNonWettingIntermediateCapPresTableNameString(),
+ &m_drainageNonWettingIntermediateCapPresTableName ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription(
+ "Drainage non-wetting/intermediate (e.g. o/g) capillary pressure table name for the non-wetting phase.\n"
+ "To neglect hysteresis on this phase, just use the same table name for the drainage and imbibition curves" );
+ registerWrapper( viewKeyStruct::imbibitionWettingIntermediateCapPresTableNameString(),
+ &m_imbibitionWettingIntermediateCapPresTableName ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Imbibition wetting/intermediate (e.g. w/o) table name for the wetting phase.\n"
+ "To neglect hysteresis on this phase, just use the same table name for the drainage and imbibition curves" );
+ registerWrapper( viewKeyStruct::imbibitionNonWettingIntermediateCapPresTableNameString(),
+ &m_imbibitionNonWettingIntermediateCapPresTableName ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Imbibition non-wetting/intermediate (e.g. o/g) table name for the wetting phase.\n"
+ "To neglect hysteresis on this phase, just use the same table name for the drainage and imbibition curves" );
+
+ // kernels
+ //2p
+ registerWrapper( viewKeyStruct::wettingNonWettingCapillaryPressureKernelWrappersString(),
+ &m_wettingNonWettingCapillaryPressureKernelWrappers )
+ .setSizedFromParent( 0 ).setRestartFlags( RestartFlags::NO_WRITE );
+ //3p
+ registerWrapper( viewKeyStruct::wettingIntermediateCapillaryPressureKernelWrappersString(),
+ &m_wettingIntermediateCapillaryPressureKernelWrappers )
+ .setSizedFromParent( 0 ).setRestartFlags( RestartFlags::NO_WRITE );
+ registerWrapper( viewKeyStruct::nonWettingIntermediateCapillaryPressureKernelWrappersString(),
+ &m_nonWettingIntermediateCapillaryPressureKernelWrappers )
+ .setSizedFromParent( 0 ).setRestartFlags( RestartFlags::NO_WRITE );
+
+
+ registerWrapper( viewKeyStruct::wettingCurveString(), &m_wettingCurve ).
+ setInputFlag(
+ InputFlags::FALSE ). // will be deduced from tables
+ setSizedFromParent(
+ 0 )
+ .setRestartFlags( RestartFlags::NO_WRITE );
+
+ registerWrapper( viewKeyStruct::nonWettingCurveString(), &m_nonWettingCurve ).
+ setInputFlag(
+ InputFlags::FALSE ). // will be deduced from tables
+ setSizedFromParent(
+ 0 )
+ .setRestartFlags( RestartFlags::NO_WRITE );
+
+ //Forwarded to KilloughHysteresis
+ registerWrapper( KilloughHysteresis::viewKeyStruct::jerauldParameterAString(), &m_jerauldParam_a ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setApplyDefaultValue( 0.1 ).
+ setDescription(
+ "First parameter (modification parameter) introduced by Jerauld in the Land trapping model (see RTD documentation)." );
+
+ registerWrapper( KilloughHysteresis::viewKeyStruct::jerauldParameterBString(), &m_jerauldParam_b ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setApplyDefaultValue( 0.0 ).
+ setDescription(
+ "Second parameter (modification parameter) introduced by Jerauld in the Land trapping model (see RTD documentation)." );
+
+
+ registerWrapper( KilloughHysteresis::viewKeyStruct::killoughCurvatureParameterPcString(),
+ &m_killoughCurvatureParamCapPres ).
+ setInputFlag(
+ InputFlags::OPTIONAL ).
+ setApplyDefaultValue(
+ .1 ).
+ setDescription(
+ "Curvature parameter introduced by Killough for wetting-phase hysteresis (see RTD documentation)." );
+
+ //misc
+ registerWrapper( viewKeyStruct::phaseIntermediateMinVolFractionString(), &m_phaseIntermediateMinVolFraction ).
+ setInputFlag( InputFlags::FALSE ).setDescription( "min vol fraction of intermediate if exist" ).
+ // will be deduced from tables
+ setSizedFromParent( 0 );
+
+ registerField< fields::cappres::mode >( &m_mode );
+
+
+ registerField< fields::cappres::phaseMaxHistoricalVolFraction >(
+ &m_phaseMaxHistoricalVolFraction );
+ registerField< fields::cappres::phaseMinHistoricalVolFraction >(
+ &m_phaseMinHistoricalVolFraction );
+ registerField< fields::cappres::phaseMode2PeakVolFraction >(
+ &m_phaseMode2PeakVolFraction );
+
+}
+
+/// usual utils
+
+void TableCapillaryPressureHysteresis::postProcessInput()
+{
+
+ using TPP = ThreePhasePairPhaseType;
+
+ integer const numPhases = m_phaseNames.size();
+ GEOS_THROW_IF( numPhases != 2 && numPhases != 3,
+ GEOS_FMT( "{}: the expected number of fluid phases is either two, or three",
+ getFullName()),
+ InputError );
+
+ m_phaseHasHysteresis.resize( 2 );
+
+ if( numPhases == 2 )
+ {
+ GEOS_THROW_IF( m_drainageWettingNonWettingCapPresTableName.empty(),
+ GEOS_FMT(
+ "{}: for a two-phase flow simulation, we must use {} to specify the capillary pressure table for the drainage pair (wetting phase, non-wetting phase)",
+ getFullName(),
+ viewKeyStruct::drainageWettingNonWettingCapPresTableNameString()),
+ InputError );
+
+
+ m_phaseHasHysteresis[TPP::INTERMEDIATE_WETTING] = (m_imbibitionWettingNonWettingCapPresTableName.empty() ||
+ m_imbibitionWettingNonWettingCapPresTableName ==
+ m_drainageWettingNonWettingCapPresTableName)
+ ? 0 : 1;
+ m_phaseHasHysteresis[TPP::INTERMEDIATE_NONWETTING] = m_phaseHasHysteresis[TPP::INTERMEDIATE_WETTING];
+
+
+ }
+ else if( numPhases == 3 )
+ {
+
+
+ GEOS_THROW_IF( m_drainageWettingIntermediateCapPresTableName.empty() ||
+ m_drainageNonWettingIntermediateCapPresTableName.empty(),
+ GEOS_FMT(
+ "{}: for a three-phase flow simulation, we must use {} to specify the capillary pressure table "
+ "for the pair (wetting phase, intermediate phase), and {} to specify the capillary pressure table "
+ "for the pair (non-wetting phase, intermediate phase)",
+ getFullName(),
+ viewKeyStruct::drainageWettingIntermediateCapPresTableNameString(),
+ viewKeyStruct::drainageNonWettingIntermediateCapPresTableNameString()),
+ InputError );
+
+ m_phaseHasHysteresis[TPP::INTERMEDIATE_WETTING] = (m_imbibitionWettingIntermediateCapPresTableName.empty() ||
+ m_imbibitionWettingIntermediateCapPresTableName ==
+ m_drainageWettingIntermediateCapPresTableName)
+ ? 0 : 1;
+
+ m_phaseHasHysteresis[TPP::INTERMEDIATE_NONWETTING] = (m_imbibitionNonWettingIntermediateCapPresTableName.empty() ||
+ m_imbibitionNonWettingIntermediateCapPresTableName ==
+ m_drainageNonWettingIntermediateCapPresTableName)
+ ? 0 : 1;
+ }
+ //Killough section
+ //TODO improve hard coded default
+ KilloughHysteresis::postProcessInput( m_jerauldParam_a, m_jerauldParam_b, 0,
+ m_killoughCurvatureParamCapPres );
+
+ GEOS_THROW_IF( m_phaseHasHysteresis[TPP::INTERMEDIATE_WETTING] == 0 &&
+ m_phaseHasHysteresis[TPP::INTERMEDIATE_NONWETTING] == 0,
+ GEOS_FMT(
+ "{}: we must use {} (2-phase) / {} or {} (3-phase) to specify at least one imbibition relative permeability table",
+ getFullName(),
+ viewKeyStruct::imbibitionWettingNonWettingCapPresTableNameString(),
+ viewKeyStruct::imbibitionWettingIntermediateCapPresTableNameString(),
+ viewKeyStruct::imbibitionNonWettingIntermediateCapPresTableNameString()),
+ InputError );
+
+}
+
+void TableCapillaryPressureHysteresis::initializePreSubGroups()
+{
+ CapillaryPressureBase::initializePreSubGroups();
+
+ integer const numPhases = m_phaseNames.size();
+ FunctionManager const & functionManager = FunctionManager::getInstance();
+
+ //equivalent to oil/gas - a.k.a two phase flow ordered by non wetting
+ bool const capPresMustBeIncreasing = (m_phaseOrder[PhaseType::WATER] < 0)
+ ? true // pc on the gas phase, function must be increasing
+ : false; // pc on the water phase, function must be decreasing
+
+
+ // Step 1: check sanity of drainage tables
+ if( numPhases == 2 )
+ {
+
+ real64 drainageWettingPhaseMaxVolumeFraction, drainageWettingMinCapPres,
+ drainageNonWettingPhaseMinVolumeFraction, drainageNonWettingMinCapPres,
+ imbibitionWettingPhaseMaxVolumeFraction, imbibitionWettingMinCapPres,
+ imbibitionNonWettingPhaseMinVolumeFraction, imbibitionNonWettingMinCapPres,
+ wettingPhaseMinVolumeFraction, wettingMaxCapPres,
+ nonWettingPhaseMaxVolumeFraction, nonWettingMaxCapPres;
+
+ {
+
+ imbibitionNonWettingMinCapPres = 0.0;
+
+ GEOS_THROW_IF( !functionManager.hasGroup( m_drainageWettingNonWettingCapPresTableName ),
+ GEOS_FMT( "{}: the table function named {} could not be found",
+ getFullName(),
+ m_drainageWettingNonWettingCapPresTableName ),
+ InputError );
+ TableFunction const
+ & capPresTable = functionManager.getGroup< TableFunction >(
+ m_drainageWettingNonWettingCapPresTableName );
+
+ //w/o or w/g pair
+ if( !capPresMustBeIncreasing )
+ {
+ TableCapillaryPressureHelpers::validateCapillaryPressureTable( capPresTable, getFullName(),
+ capPresMustBeIncreasing,
+ drainageWettingPhaseMaxVolumeFraction,
+ wettingPhaseMinVolumeFraction,
+ drainageWettingMinCapPres,
+ wettingMaxCapPres );
+
+ drainageNonWettingPhaseMinVolumeFraction = 1. - drainageWettingPhaseMaxVolumeFraction;
+ nonWettingPhaseMaxVolumeFraction = 1. - wettingPhaseMinVolumeFraction;
+
+ }
+ else // o/g pair
+ {
+ TableCapillaryPressureHelpers::validateCapillaryPressureTable( capPresTable, getFullName(),
+ capPresMustBeIncreasing,
+ nonWettingPhaseMaxVolumeFraction,
+ drainageNonWettingPhaseMinVolumeFraction,
+ nonWettingMaxCapPres,
+ drainageNonWettingMinCapPres );
+
+ drainageWettingPhaseMaxVolumeFraction = 1. - drainageNonWettingPhaseMinVolumeFraction;
+ wettingPhaseMinVolumeFraction = 1. - nonWettingPhaseMaxVolumeFraction;
+ }
+
+ }
+
+ {
+ GEOS_THROW_IF( !functionManager.hasGroup( m_imbibitionWettingNonWettingCapPresTableName ),
+ GEOS_FMT( "{}: the table function named {} could not be found",
+ getFullName(),
+ m_imbibitionWettingNonWettingCapPresTableName ),
+ InputError );
+ TableFunction const
+ & capPresTable = functionManager.getGroup< TableFunction >(
+ m_imbibitionWettingNonWettingCapPresTableName );
+
+ //w/o or w/g pair
+ if( !capPresMustBeIncreasing )
+ {
+ TableCapillaryPressureHelpers::validateCapillaryPressureTable( capPresTable, getFullName(),
+ capPresMustBeIncreasing,
+ imbibitionWettingPhaseMaxVolumeFraction,
+ wettingPhaseMinVolumeFraction,
+ imbibitionWettingMinCapPres,
+ wettingMaxCapPres );
+
+ imbibitionNonWettingPhaseMinVolumeFraction = 1. - imbibitionWettingPhaseMaxVolumeFraction;
+ nonWettingPhaseMaxVolumeFraction = 1. - wettingPhaseMinVolumeFraction;
+
+ }
+ else // o/g pair
+ {
+ TableCapillaryPressureHelpers::validateCapillaryPressureTable( capPresTable, getFullName(),
+ capPresMustBeIncreasing,
+ nonWettingPhaseMaxVolumeFraction,
+ imbibitionNonWettingPhaseMinVolumeFraction,
+ nonWettingMaxCapPres,
+ imbibitionWettingMinCapPres );
+
+ imbibitionWettingPhaseMaxVolumeFraction = 1. - imbibitionNonWettingPhaseMinVolumeFraction;
+ wettingPhaseMinVolumeFraction = 1. - nonWettingPhaseMaxVolumeFraction;
+ }
+ }
+
+ //constructing wetting/nonwetting curves
+
+ if( !capPresMustBeIncreasing )
+ {
+ m_wettingCurve.setPoints(
+ {wettingPhaseMinVolumeFraction, wettingMaxCapPres}, // same as imbibition min
+ {imbibitionWettingPhaseMaxVolumeFraction, imbibitionWettingMinCapPres},
+ {drainageWettingPhaseMaxVolumeFraction, drainageWettingMinCapPres} );
+ }
+ else
+ {
+ m_nonWettingCurve.setPoints(
+ {nonWettingPhaseMaxVolumeFraction, nonWettingMaxCapPres},
+ {imbibitionNonWettingPhaseMinVolumeFraction, imbibitionNonWettingMinCapPres},
+ {drainageNonWettingPhaseMinVolumeFraction, drainageNonWettingMinCapPres}
+ );
+ }
+
+ }
+ else if( numPhases == 3 )
+ {
+
+ real64 drainageWettingPhaseMaxVolumeFraction, drainageWettingMinCapPres,
+ drainageNonWettingPhaseMinVolumeFraction, drainageNonWettingMinCapPres,
+ imbibitionWettingPhaseMaxVolumeFraction, imbibitionWettingMinCapPres,
+ imbibitionNonWettingPhaseMinVolumeFraction, imbibitionNonWettingMinCapPres,
+ wettingPhaseMinVolumeFraction, wettingMaxCapPres,
+ nonWettingPhaseMaxVolumeFraction, nonWettingMaxCapPres;
+
+ GEOS_UNUSED_VAR( drainageWettingMinCapPres );
+//define scope to avoid differentiate temp var (lazy)
+ {
+ GEOS_THROW_IF( !functionManager.hasGroup( m_drainageWettingIntermediateCapPresTableName ),
+ GEOS_FMT( "{}: the table function named {} could not be found",
+ getFullName(),
+ m_drainageWettingIntermediateCapPresTableName ),
+ InputError );
+ TableFunction const
+ & capPresTableWI = functionManager.getGroup< TableFunction >(
+ m_drainageWettingIntermediateCapPresTableName );
+ TableCapillaryPressureHelpers::validateCapillaryPressureTable( capPresTableWI, getFullName(), false,
+ drainageWettingPhaseMaxVolumeFraction,
+ wettingPhaseMinVolumeFraction,
+ drainageNonWettingMinCapPres,
+ wettingMaxCapPres );
+
+ GEOS_THROW_IF( !functionManager.hasGroup( m_drainageNonWettingIntermediateCapPresTableName ),
+ GEOS_FMT( "{}: the table function named {} could not be found",
+ getFullName(),
+ m_drainageNonWettingIntermediateCapPresTableName ),
+ InputError );
+ TableFunction const & capPresTableNWI =
+ functionManager.getGroup< TableFunction >( m_drainageNonWettingIntermediateCapPresTableName );
+ TableCapillaryPressureHelpers::validateCapillaryPressureTable( capPresTableNWI, getFullName(), true,
+ nonWettingPhaseMaxVolumeFraction,
+ drainageNonWettingPhaseMinVolumeFraction,
+ nonWettingMaxCapPres,
+ drainageWettingPhaseMaxVolumeFraction
+ );
+
+ m_phaseIntermediateMinVolFraction =
+ 1.0 - drainageWettingPhaseMaxVolumeFraction - drainageWettingPhaseMaxVolumeFraction;
+ }
+
+ if( !m_imbibitionWettingIntermediateCapPresTableName.empty())
+ {
+
+ GEOS_THROW_IF( !functionManager.hasGroup( m_imbibitionWettingIntermediateCapPresTableName ),
+ GEOS_FMT( "{}: the table function named {} could not be found",
+ getFullName(),
+ m_imbibitionWettingIntermediateCapPresTableName ),
+ InputError );
+ TableFunction const
+ & capPresTableWI = functionManager.getGroup< TableFunction >(
+ m_imbibitionWettingIntermediateCapPresTableName );
+ TableCapillaryPressureHelpers::validateCapillaryPressureTable( capPresTableWI, getFullName(), false,
+ imbibitionWettingPhaseMaxVolumeFraction,
+ wettingPhaseMinVolumeFraction,
+ imbibitionWettingMinCapPres,
+ wettingMaxCapPres
+ );
+
+
+ }
+
+ if( !m_imbibitionNonWettingIntermediateCapPresTableName.empty())
+ {
+
+ GEOS_THROW_IF( !functionManager.hasGroup( m_imbibitionNonWettingIntermediateCapPresTableName ),
+ GEOS_FMT( "{}: the table function named {} could not be found",
+ getFullName(),
+ m_imbibitionNonWettingIntermediateCapPresTableName ),
+ InputError );
+ TableFunction const & capPresTableNWI =
+ functionManager.getGroup< TableFunction >( m_imbibitionNonWettingIntermediateCapPresTableName );
+ TableCapillaryPressureHelpers::validateCapillaryPressureTable( capPresTableNWI, getFullName(), true,
+ nonWettingPhaseMaxVolumeFraction,
+ imbibitionNonWettingPhaseMinVolumeFraction,
+ nonWettingMaxCapPres,
+ imbibitionNonWettingMinCapPres );
+
+
+ }
+ }
+
+ // Step 2: check the sanity btw drainage and imbibition
+ auto const eps = 1e-15;
+ if( numPhases == 2 )
+ {
+ //TODO weak make stronger
+ GEOS_THROW_IF(
+ m_wettingCurve.isZero() && m_nonWettingCurve.isZero(),
+ GEOS_FMT(
+ "{}: Inconsistent data for capillary pressure hysteresis. No hysteresis curve is defined.",
+ getFullName()),
+ InputError );
+
+ GEOS_THROW_IF(
+ !m_wettingCurve.isZero() && !m_nonWettingCurve.isZero(),
+ GEOS_FMT(
+ "{}: Inconsistent data for capillary pressure hysteresis. Both non wetting and wetting hysteresis curve are defined in two phase flow setting.",
+ getFullName()),
+ InputError );
+
+
+ }
+ else if( numPhases == 3 )
+ {
+
+ GEOS_THROW_IF( std::fabs( m_wettingCurve.oppositeBoundPhaseVolFraction - (1. - m_nonWettingCurve.oppositeBoundPhaseVolFraction - m_phaseIntermediateMinVolFraction)) > eps,
+ GEOS_FMT(
+ "{}: Inconsistent data for capillary pressure hysteresis. {}, {} and {} should sum up to 1.",
+ getFullName(), "Sw_min", "Snw_max", "Sinter_min" ),
+ InputError );
+ GEOS_THROW_IF( std::fabs( m_wettingCurve.drainageExtremaPhaseVolFraction - (1. - m_nonWettingCurve.drainageExtremaPhaseVolFraction - m_phaseIntermediateMinVolFraction)) > eps,
+ GEOS_FMT(
+ "{}: Inconsistent data for capillary pressure hysteresis. {}, {} and {} should sum up to 1.",
+ getFullName(), "Sw_min", "Snw_max", "Sinter_min" ),
+ InputError );
+ GEOS_THROW_IF( std::fabs( m_wettingCurve.imbibitionExtremaPhaseVolFraction - (1. - m_nonWettingCurve.imbibitionExtremaPhaseVolFraction - m_phaseIntermediateMinVolFraction)) > eps,
+ GEOS_FMT(
+ "{}: Inconsistent data for capillary pressure hysteresis. {}, {} and {} should sum up to 1.",
+ getFullName(), "Sw_min", "Snw_max", "Sinter_min" ),
+ InputError );
+
+ }
+
+
+ // Step 3: compute the Land coefficient
+ computeLandCoefficient();
+
+
+
+ if( m_phaseMaxHistoricalVolFraction.size( 1 ) == 0 && numPhases > 0 )
+ {
+ localIndex const currentSize = m_phaseMaxHistoricalVolFraction.size( 0 );
+ if( currentSize > 0 )
+ {
+ m_phaseMaxHistoricalVolFraction.resize( currentSize, numPhases );
+ m_phaseMinHistoricalVolFraction.resize( currentSize, numPhases );
+ m_phaseMode2PeakVolFraction.resize( currentSize, numPhases );
+ m_phaseMaxHistoricalVolFraction.setValues< parallelDevicePolicy<> >( 0.0 );
+ m_phaseMinHistoricalVolFraction.setValues< parallelDevicePolicy<> >( 1.0 );
+ m_phaseMode2PeakVolFraction.setValues< parallelDevicePolicy<> >( 0.0 );
+ }
+ }
+}
+
+/// Land coeff (tb refactored out in KilloughHysteresis) and saved cvgd
+
+void TableCapillaryPressureHysteresis::computeLandCoefficient()
+{
+ // For now, we keep two separate Land parameters for the wetting and non-wetting phases
+ // For two-phase flow, we make sure that they are equal
+ m_landParam.resize( 2 );
+
+ // Note: for simplicity, the notations are taken from IX documentation (although this breaks our phaseVolFrac naming convention)
+
+ // Step 1: Land parameter for the wetting phase
+
+ integer ipWetting, ipNonWetting;
+ std::tie( ipWetting, ipNonWetting ) = phaseIndex( m_phaseOrder );
+
+ KilloughHysteresis::computeLandCoefficient( m_wettingCurve, m_landParam[ipWetting] );
+ KilloughHysteresis::computeLandCoefficient( m_nonWettingCurve, m_landParam[ipNonWetting] );
+
+}
+
+/// common utils
+void TableCapillaryPressureHysteresis::resizeFields( localIndex const size, localIndex const numPts )
+{
+ CapillaryPressureBase::resizeFields( size, numPts );
+
+ integer const numPhases = numFluidPhases();
+
+
+
+ m_mode.resize( size );
+
+ if( numPhases > 0 )
+ {
+ m_phaseMaxHistoricalVolFraction.resize( size, numPhases );
+ m_phaseMinHistoricalVolFraction.resize( size, numPhases );
+ m_phaseMode2PeakVolFraction.resize( size, numPhases );
+ m_phaseMaxHistoricalVolFraction.setValues< parallelDevicePolicy<> >( 0.0 );
+ m_phaseMinHistoricalVolFraction.setValues< parallelDevicePolicy<> >( 1.0 );
+ m_phaseMode2PeakVolFraction.setValues< parallelDevicePolicy<> >( 0.0 );
+ }
+
+
+}
+
+void TableCapillaryPressureHysteresis::saveConvergedPhaseVolFractionState(
+ arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFraction ) const
+{
+ CapillaryPressureBase::saveConvergedState();
+
+ arrayView2d< real64, compflow::USD_PHASE > phaseMaxHistoricalVolFraction = m_phaseMaxHistoricalVolFraction.toView();
+ arrayView2d< real64, compflow::USD_PHASE > phaseMinHistoricalVolFraction = m_phaseMinHistoricalVolFraction.toView();
+ arrayView2d< real64, compflow::USD_PHASE > phaseMode2PeakVolFraction = m_phaseMode2PeakVolFraction.toView();
+ arrayView1d< integer > mode_int = m_mode.toView();
+
+ localIndex const numElems = phaseVolFraction.size( 0 );
+ integer const numPhases = numFluidPhases();
+
+
+
+ using PT = CapillaryPressureBase::PhaseType;
+ arrayView1d< integer const > const phaseOrderView = phaseOrder();
+ integer const ipWater = phaseOrderView[PT::WATER];
+ integer const ipOil = phaseOrderView[PT::OIL];
+ integer const ipGas = phaseOrderView[PT::GAS];
+
+ integer ipWetting = -1;
+ if( ipWater >= 0 && ipOil >= 0 && ipGas >= 0 )
+ {
+ ipWetting = ipWater;
+ }
+ else if( ipWater < 0 )
+ {
+ ipWetting = ipOil;
+ }
+ else if( ipOil < 0 )
+ {
+ ipWetting = ipWater;
+ }
+ else if( ipGas < 0 )
+ {
+ ipWetting = ipWater;
+ }
+
+ forAll< parallelDevicePolicy<> >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) {
+ for( integer ip = 0; ip < numPhases; ++ip )
+ {
+ phaseMaxHistoricalVolFraction[ei][ip] = LvArray::math::max( phaseVolFraction[ei][ip],
+ phaseMaxHistoricalVolFraction[ei][ip] );
+ phaseMinHistoricalVolFraction[ei][ip] = LvArray::math::min( phaseVolFraction[ei][ip],
+ phaseMinHistoricalVolFraction[ei][ip] );
+ }
+
+ if( ipWetting >= 0 && ipWetting < numPhases )
+ {
+ ModeIndexType const currentMode = static_cast< ModeIndexType >(mode_int[ei]);
+ if( currentMode == ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ real64 const currentS = phaseVolFraction[ei][ipWetting];
+ if( currentS > phaseMode2PeakVolFraction[ei][ipWetting] )
+ {
+ phaseMode2PeakVolFraction[ei][ipWetting] = currentS;
+ }
+ }
+ else if( currentMode != ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ phaseMode2PeakVolFraction[ei][ipWetting] = 0.0;
+ }
+ }
+ } );
+
+}
+
+void
+TableCapillaryPressureHysteresis::KernelWrapper::computeImbibitionWettingCapillaryPressure(
+ const arrayView1d< const TableFunction::KernelWrapper > & wettingKernelWapper,
+ const KilloughHysteresis::HysteresisCurve & wettingCurve,
+ const KilloughHysteresis::HysteresisCurve & nonWettingCurve, //discard if not needed
+ const geos::real64 & landParam,
+ const geos::real64 & phaseVolFraction,
+ const geos::real64 & phaseMinHistoricalVolFraction,
+ const geos::real64 & phaseMaxHistoricalVolFraction,
+ const geos::real64 & phaseMode2PeakVolFraction,
+ geos::real64 & phaseTrappedVolFrac,
+ geos::real64 & phaseCapPressure,
+ geos::real64 & dPhaseCapPressure_dPhaseVolFrac,
+ const ModeIndexType & mode ) const
+{
+ GEOS_ASSERT( wettingCurve.isWetting());
+ real64 const S = phaseVolFraction;
+ real64 const Smxi = wettingCurve.imbibitionExtremaPhaseVolFraction;
+ real64 const Smxd = wettingCurve.drainageExtremaPhaseVolFraction;
+ real64 const Smin = wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Smax = wettingCurve.drainageExtremaPhaseVolFraction;
+
+ GEOS_UNUSED_VAR( Smxi, Smxd, phaseTrappedVolFrac );
+
+// if( S <= Smin )
+// {
+// //below accessible range
+// phaseCapPressure = CAP_INF;
+// dPhaseCapPressure_dPhaseVolFrac = -CAP_INF_DERIV;
+// }
+// else if( S >= Smxd )
+// {
+// //above accessible range
+// phaseCapPressure = -CAP_INF;
+// dPhaseCapPressure_dPhaseVolFrac = -CAP_INF_DERIV;
+// }
+// else
+ {
+ //drainage to imbibition
+ real64 dpci_dS, dpcd_dS;
+ real64 const pci = wettingKernelWapper[ModeIndexType::IMBIBITION].compute( &S, &dpci_dS );
+ real64 const pcd = wettingKernelWapper[ModeIndexType::DRAINAGE].compute( &S, &dpcd_dS );
+ real64 const Somin = m_phaseIntermediateMinVolFraction;
+
+ real64 const E = m_killoughCurvatureParamCapPres;
+
+ //Step 2. compute F as in (EQ 34.15) F = (1/(Sw-Shy+E)-1/E) / (1/(Swma-Shy+E)-1/E)
+ //drainage to imbibition branch
+ if( mode == ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // DRAINAGE_TO_IMBIBITION: Shy should be minimum historical (where drainage started)
+ real64 const Shy = (phaseMinHistoricalVolFraction > Smin) ? phaseMinHistoricalVolFraction : Smin;
+
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( nonWettingCurve,
+ Shy,
+ landParam,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ Scrt );
+ real64 const Swma = 1 - Scrt - Somin;
+ real64 F = (1. / (S - Shy + E) - 1. / E) / (1. / (Swma - Shy + E) - 1. / E);
+ //force bound
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ //Step 3. Eventually assemble everything following (EQ. 34.14)
+ phaseCapPressure = pcd + F * (pci - pcd);
+ dPhaseCapPressure_dPhaseVolFrac = dpcd_dS + F * (dpci_dS - dpcd_dS);
+ }
+ //imbibition to drainage
+ else if( mode == ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // IMBIBITION_TO_DRAINAGE: Shy should be maximum historical (where imbibition started)
+ real64 const Shy = (phaseMaxHistoricalVolFraction < Smax) ? phaseMaxHistoricalVolFraction : Smax;
+
+ // For IMBIBITION_TO_DRAINAGE, use the same formula structure as non-wetting phase
+ // F = (1. / (S - Shy + E) - 1. / E) / (1. / (Swmin - Shy + E) - 1. / E)
+ // This ensures F = 0 when S = Shy (high saturation) and F = 1 when S = Swmin (low saturation)
+ // Minimum accessible wetting saturation = Somin (irreducible wetting saturation)
+ // Use actual Somin (may be 0.0), the formula will handle negative values correctly
+ real64 const Swmin = Somin;
+
+ real64 const F_num = (1. / (S - Shy + E) - 1. / E);
+ real64 const F_denom = (1. / (Swmin - Shy + E) - 1. / E);
+ // Both numerator and denominator can be negative when Swmin < Shy - E
+ // This is okay - negative/negative = positive F
+ real64 F = F_num / F_denom;
+ //force bound
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ //Step 3. Eventually assemble everything following (EQ. 34.14)
+ phaseCapPressure = pci + F * (pcd - pci);
+ dPhaseCapPressure_dPhaseVolFrac = dpci_dS + F * (dpcd_dS - dpci_dS);
+ }
+ //imbibition to drainage from scanning curve (departing from DRAINAGE_TO_IMBIBITION)
+ else if( mode == ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ // IMBIBITION_TO_DRAINAGE_FROM_SCANNING: Secondary drainage scanning curve
+ // Based on Killough (1976) - solve quadratic for ghost departure point
+ //
+ // Nomenclature:
+ // - Sw_star (S_star): second reversal saturation (turnaround point, peak reached during Mode 2)
+ // - Sw_Hyst_imb (H): first reversal point (where imbibition started, departure from drainage)
+ // - Sw_wr (Sw_wr): residual/connate wetting saturation
+ // - x (Sw_star_Hyst_ghost): ghost departure point on imbibition curve (unknown, to be solved)
+ //
+ // Step 1: Identify reversal points
+ // S_star is the turnaround point (peak reached during Mode 2)
+ real64 S_star = phaseMode2PeakVolFraction;
+ if( S_star < 1e-12 || S_star >= Smax - 1e-12 )
+ {
+ // Use phaseMaxHistoricalVolFraction, but ensure it's between H and Smax
+ real64 const H_temp = (phaseMinHistoricalVolFraction > Smin) ? phaseMinHistoricalVolFraction : Smin;
+ if( phaseMaxHistoricalVolFraction > H_temp + 1e-12 && phaseMaxHistoricalVolFraction < Smax - 1e-12 )
+ {
+ S_star = phaseMaxHistoricalVolFraction;
+ }
+ else
+ {
+ S_star = LvArray::math::max( H_temp + 0.1, LvArray::math::min( S, Smax - 0.01 ));
+ }
+ }
+
+ real64 const H = (phaseMinHistoricalVolFraction > Smin) ? phaseMinHistoricalVolFraction : Smin;
+ // Sw_wr: residual/connate wetting saturation - minimum saturation on drainage curve
+ // For wetting phase, oppositeBoundPhaseVolFraction should be the minimum, but if it's 0,
+ // we need to get the actual minimum from the drainage curve table
+ // Since we can't easily access table coordinates from KernelWrapper, use Smin if > 0, otherwise try Somin
+ real64 Sw_wr = Smin;
+ if( Sw_wr < 1e-12 )
+ {
+ Sw_wr = (Somin > 1e-12) ? Somin : 1e-6; // Small default to avoid division issues
+ }
+
+ // Step 2: Compute F_known from Mode 2 (imbibition scanning curve) at S_star
+ // Mode 2 formula: F = (1 / (S - H + E) - 1 / E) / (1 / (Swma - H + E) - 1 / E)
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( nonWettingCurve,
+ H,
+ landParam,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ Scrt );
+ real64 const Swma = 1 - Scrt - Somin;
+ real64 F_known = 0.0;
+ if( S_star <= Swma + 1e-12 )
+ {
+ real64 const F_num = (1. / (S_star - H + E) - 1. / E);
+ real64 const F_denom = (1. / (Swma - H + E) - 1. / E);
+ if( LvArray::math::abs( F_denom ) > 1e-12 )
+ {
+ F_known = F_num / F_denom;
+ }
+ else
+ {
+ F_known = (S_star > H) ? 1.0 : 0.0;
+ }
+ }
+ else
+ {
+ // S_star > Swma: beyond Mode 2 range, use F_known = 0 (pure imbibition)
+ F_known = 0.0;
+ }
+ F_known = LvArray::math::max( 0.0, LvArray::math::min( 1.0, F_known ));
+
+ // Step 3: Compute F_star_target = 1 - F_known (from Eq. A-6)
+ real64 const F_star_target = 1.0 - F_known;
+
+ // Step 4: Solve quadratic for x = Sw_star_Hyst_ghost
+ // F* = [1/(x - S_star + E) - 1/E] / [1/(x - H + E) - 1/E] = F_star_target
+ // Note: Denominator uses H (first reversal point), not Sw_wr, so curve rejoins drainage at H
+ // Rearranging gives: (1-T)*x^2 + B*x + C = 0
+ // where T = F_star_target, a = S_star, b = H, e = E
+ real64 const a = S_star;
+ real64 const b = H; // Use H instead of Sw_wr so curve rejoins drainage at H
+ real64 const e = E;
+ real64 const T = F_star_target;
+
+ real64 const coeff_A = (1.0 - T);
+ real64 const coeff_B = -(1.0 - T) * (a + b - 2.0 * e) - (1.0 - T) * e;
+ real64 const coeff_C = (1.0 - T) * (a - e) * (b - e)
+ - e * e * (1.0 + T)
+ - e * (T * a - b);
+
+ real64 x = S_star;
+ real64 discriminant = coeff_B * coeff_B - 4.0 * coeff_A * coeff_C;
+
+ if( discriminant >= 0.0 && LvArray::math::abs( coeff_A ) > 1e-14 )
+ {
+ real64 sqrt_disc = LvArray::math::sqrt( discriminant );
+ real64 x1 = (-coeff_B + sqrt_disc) / (2.0 * coeff_A);
+ real64 x2 = (-coeff_B - sqrt_disc) / (2.0 * coeff_A);
+
+ // Pick the physically meaningful root: x must be > S_star
+ if( x1 > S_star - 1e-8 && x2 > S_star - 1e-8 )
+ {
+ x = LvArray::math::min( x1, x2 ); // Take the closer one
+ }
+ else if( x1 > S_star - 1e-8 )
+ {
+ x = x1;
+ }
+ else if( x2 > S_star - 1e-8 )
+ {
+ x = x2;
+ }
+ }
+
+ // Step 5: Compute F_star for current saturation S
+ // F_star = [1/(x - S + E) - 1/E] / [1/(x - H + E) - 1/E]
+ // When S = H, F_star = 1.0 (pure drainage), so curve rejoins drainage at H
+ real64 F_star = 1.0;
+ real64 F_star_num = (1. / (x - S + E) - 1. / E);
+ real64 F_star_denom = (1. / (x - H + E) - 1. / E);
+ if( LvArray::math::abs( F_star_denom ) > 1e-12 )
+ {
+ F_star = F_star_num / F_star_denom;
+ F_star = LvArray::math::max( 0.0, LvArray::math::min( 1.0, F_star ));
+ }
+
+ // Step 6: Compute Pc using Eq. A-5: P_c = P_c^Im + F* [P_c^Dr - P_c^Im]
+ phaseCapPressure = pci + F_star * (pcd - pci);
+ dPhaseCapPressure_dPhaseVolFrac = dpci_dS + F_star * (dpcd_dS - dpci_dS);
+ }
+ else
+ {
+ GEOS_THROW( GEOS_FMT( "{}: State is {}.Shouldnt be used in pure DRAINAGE or IMBIBITION.",
+ "TableCapillaryPressureHysteresis",
+ (mode == ModeIndexType::DRAINAGE) ? "DRAINAGE" : ((mode ==
+ ModeIndexType::IMBIBITION)
+ ? "IMBIBITION"
+ : "UNKNOWN")),
+ InputError );
+ }
+
+
+ }
+
+}
+
+void
+TableCapillaryPressureHysteresis::KernelWrapper::computeImbibitionWettingCapillaryPressure(
+ const arrayView1d< const TableFunction::KernelWrapper > & wettingKernelWapper,
+ const KilloughHysteresis::HysteresisCurve & wettingCurve,
+ const geos::real64 & landParam,
+ const geos::real64 & phaseVolFraction,
+ const geos::real64 & phaseMinHistoricalVolFraction,
+ const geos::real64 & phaseMaxHistoricalVolFraction,
+ const geos::real64 & phaseMode2PeakVolFraction,
+ geos::real64 & phaseTrappedVolFrac,
+ geos::real64 & phaseCapPressure,
+ geos::real64 & dPhaseCapPressure_dPhaseVolFrac,
+ const ModeIndexType & mode ) const
+{
+ GEOS_ASSERT( wettingCurve.isWetting());
+ real64 const S = phaseVolFraction;
+ real64 const Smxi = wettingCurve.imbibitionExtremaPhaseVolFraction;
+ real64 const Smxd = wettingCurve.drainageExtremaPhaseVolFraction;
+ real64 const Smin = wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Smax = wettingCurve.drainageExtremaPhaseVolFraction;
+
+ GEOS_UNUSED_VAR( Smxi, Smxd, phaseTrappedVolFrac );
+
+// if( S <= Smin )
+// {
+// //below accessible range
+// phaseCapPressure = CAP_INF;
+// dPhaseCapPressure_dPhaseVolFrac = -CAP_INF_DERIV;
+// }
+// else if( S >= Smxd )
+// {
+// //above accessible range
+// phaseCapPressure = -CAP_INF;
+// dPhaseCapPressure_dPhaseVolFrac = -CAP_INF_DERIV;
+// }
+// else
+ {
+ //drainage to imbibition
+ real64 dpci_dS, dpcd_dS;
+ real64 const pci = wettingKernelWapper[ModeIndexType::IMBIBITION].compute( &S, &dpci_dS );
+ real64 const pcd = wettingKernelWapper[ModeIndexType::DRAINAGE].compute( &S, &dpcd_dS );
+
+ real64 const Somin = m_phaseIntermediateMinVolFraction;
+ real64 const E = m_killoughCurvatureParamCapPres;
+
+ //Step 2. compute F as in (EQ 34.15) F = (1/(Sw-Shy+E)-1/E) / (1/(Swma-Shy+E)-1/E)
+ //drainage to imbibition branch
+ if( mode == ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // DRAINAGE_TO_IMBIBITION: Shy should be minimum historical (where drainage started)
+ real64 const Shy = (phaseMinHistoricalVolFraction > Smin) ? phaseMinHistoricalVolFraction : Smin;
+
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( wettingCurve,
+ Shy,
+ landParam,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ Scrt );
+
+
+
+ //should be the pore space accessible to the two wetting phase
+ real64 const Swma = 1 - (1 - Scrt);
+ real64 F = (1. / (S - Shy + E) - 1. / E) / (1. / (Swma - Shy + E) - 1. / E);
+ //force bound
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ //Step 3. Eventually assemble everything following (EQ. 34.14)
+ phaseCapPressure = pcd + F * (pci - pcd);
+ dPhaseCapPressure_dPhaseVolFrac = dpcd_dS + F * (dpci_dS - dpcd_dS);
+ }
+ //imbibition to drainage
+ else if( mode == ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // IMBIBITION_TO_DRAINAGE: Shy should be maximum historical (where imbibition started)
+ real64 const Shy = (phaseMaxHistoricalVolFraction < Smax) ? phaseMaxHistoricalVolFraction : Smax;
+
+ // For IMBIBITION_TO_DRAINAGE, use the same formula structure as non-wetting phase
+ // F = (1. / (S - Shy + E) - 1. / E) / (1. / (Swmin - Shy + E) - 1. / E)
+ // This ensures F = 0 when S = Shy (high saturation) and F = 1 when S = Swmin (low saturation)
+ // For two-phase, use Smin as the minimum accessible wetting saturation
+ // Use actual Smin (may be 0.0), the formula will handle negative values correctly
+ real64 const Swmin = Smin;
+
+ real64 const F_num = (1. / (S - Shy + E) - 1. / E);
+ real64 const F_denom = (1. / (Swmin - Shy + E) - 1. / E);
+ // Both numerator and denominator can be negative when Swmin < Shy - E
+ // This is okay - negative/negative = positive F
+ real64 F = F_num / F_denom;
+ //force bound
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ //Step 3. Eventually assemble everything following (EQ. 34.14)
+ phaseCapPressure = pci + F * (pcd - pci);
+ dPhaseCapPressure_dPhaseVolFrac = dpci_dS + F * (dpcd_dS - dpci_dS);
+ }
+ //imbibition to drainage from scanning curve (departing from DRAINAGE_TO_IMBIBITION)
+ else if( mode == ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ // IMBIBITION_TO_DRAINAGE_FROM_SCANNING: Secondary drainage scanning curve
+ // Based on Killough (1976) - solve quadratic for ghost departure point
+ //
+ // Nomenclature:
+ // - Sw_star (S_star): second reversal saturation (turnaround point, peak reached during Mode 2)
+ // - Sw_Hyst_imb (H): first reversal point (where imbibition started, departure from drainage)
+ // - Sw_wr (Sw_wr): residual/connate wetting saturation
+ // - x (Sw_star_Hyst_ghost): ghost departure point on imbibition curve (unknown, to be solved)
+ //
+ // Step 1: Identify reversal points
+ // S_star is the turnaround point (peak reached during Mode 2)
+ real64 S_star = phaseMode2PeakVolFraction;
+ if( S_star < 1e-12 || S_star >= Smax - 1e-12 )
+ {
+ // Use phaseMaxHistoricalVolFraction, but ensure it's between H and Smax
+ real64 const H_temp = (phaseMinHistoricalVolFraction > Smin) ? phaseMinHistoricalVolFraction : Smin;
+ if( phaseMaxHistoricalVolFraction > H_temp + 1e-12 && phaseMaxHistoricalVolFraction < Smax - 1e-12 )
+ {
+ S_star = phaseMaxHistoricalVolFraction;
+ }
+ else
+ {
+ S_star = LvArray::math::max( H_temp + 0.1, LvArray::math::min( S, Smax - 0.01 ));
+ }
+ }
+
+ real64 const H = (phaseMinHistoricalVolFraction > Smin) ? phaseMinHistoricalVolFraction : Smin;
+ // Sw_wr: residual/connate wetting saturation - minimum saturation on drainage curve
+ // For wetting phase, oppositeBoundPhaseVolFraction should be the minimum, but if it's 0,
+ // we need to get the actual minimum from the drainage curve table
+ // Since we can't easily access table coordinates from KernelWrapper, use Smin if > 0, otherwise try Somin
+ real64 Sw_wr = Smin;
+ if( Sw_wr < 1e-12 )
+ {
+ Sw_wr = (Somin > 1e-12) ? Somin : 1e-6; // Small default to avoid division issues
+ }
+
+ // Step 2: Compute F_known from Mode 2 (imbibition scanning curve) at S_star
+ // Mode 2 formula: F = (1 / (S - H + E) - 1 / E) / (1 / (Swma - H + E) - 1 / E)
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( wettingCurve,
+ H,
+ landParam,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ Scrt );
+ real64 const Swma = 1 - (1 - Scrt); // For two-phase, following existing Mode 2 pattern
+ real64 F_known = 0.0;
+ if( S_star <= Swma + 1e-12 )
+ {
+ real64 const F_num = (1. / (S_star - H + E) - 1. / E);
+ real64 const F_denom = (1. / (Swma - H + E) - 1. / E);
+ if( LvArray::math::abs( F_denom ) > 1e-12 )
+ {
+ F_known = F_num / F_denom;
+ }
+ else
+ {
+ F_known = (S_star > H) ? 1.0 : 0.0;
+ }
+ }
+ else
+ {
+ // S_star > Swma: beyond Mode 2 range, use F_known = 0 (pure imbibition)
+ F_known = 0.0;
+ }
+ F_known = LvArray::math::max( 0.0, LvArray::math::min( 1.0, F_known ));
+
+ // Step 3: Compute F_star_target = 1 - F_known (from Eq. A-6)
+ real64 const F_star_target = 1.0 - F_known;
+
+ // Step 4: Solve quadratic for x = Sw_star_Hyst_ghost
+ // F* = [1/(x - S_star + E) - 1/E] / [1/(x - H + E) - 1/E] = F_star_target
+ // Note: Denominator uses H (first reversal point), not Sw_wr, so curve rejoins drainage at H
+ // Rearranging gives: (1-T)*x^2 + B*x + C = 0
+ // where T = F_star_target, a = S_star, b = H, e = E
+ real64 const a = S_star;
+ real64 const b = H; // Use H instead of Sw_wr so curve rejoins drainage at H
+ real64 const e = E;
+ real64 const T = F_star_target;
+
+ real64 const coeff_A = (1.0 - T);
+ real64 const coeff_B = -(1.0 - T) * (a + b - 2.0 * e) - (1.0 - T) * e;
+ real64 const coeff_C = (1.0 - T) * (a - e) * (b - e)
+ - e * e * (1.0 + T)
+ - e * (T * a - b);
+
+ real64 x = S_star;
+ real64 discriminant = coeff_B * coeff_B - 4.0 * coeff_A * coeff_C;
+
+ if( discriminant >= 0.0 && LvArray::math::abs( coeff_A ) > 1e-14 )
+ {
+ real64 sqrt_disc = LvArray::math::sqrt( discriminant );
+ real64 x1 = (-coeff_B + sqrt_disc) / (2.0 * coeff_A);
+ real64 x2 = (-coeff_B - sqrt_disc) / (2.0 * coeff_A);
+
+ // Pick the physically meaningful root: x must be > S_star
+ if( x1 > S_star - 1e-8 && x2 > S_star - 1e-8 )
+ {
+ x = LvArray::math::min( x1, x2 ); // Take the closer one
+ }
+ else if( x1 > S_star - 1e-8 )
+ {
+ x = x1;
+ }
+ else if( x2 > S_star - 1e-8 )
+ {
+ x = x2;
+ }
+ }
+
+ // Step 5: Compute F_star for current saturation S
+ // F_star = [1/(x - S + E) - 1/E] / [1/(x - H + E) - 1/E]
+ // When S = H, F_star = 1.0 (pure drainage), so curve rejoins drainage at H
+ real64 F_star = 1.0;
+ real64 F_star_num = (1. / (x - S + E) - 1. / E);
+ real64 F_star_denom = (1. / (x - H + E) - 1. / E);
+ if( LvArray::math::abs( F_star_denom ) > 1e-12 )
+ {
+ F_star = F_star_num / F_star_denom;
+ F_star = LvArray::math::max( 0.0, LvArray::math::min( 1.0, F_star ));
+ }
+
+ // Step 6: Compute Pc using Eq. A-5: P_c = P_c^Im + F* [P_c^Dr - P_c^Im]
+ phaseCapPressure = pci + F_star * (pcd - pci);
+ dPhaseCapPressure_dPhaseVolFrac = dpci_dS + F_star * (dpcd_dS - dpci_dS);
+ }
+ else
+ {
+ GEOS_THROW( GEOS_FMT( "{}: State is {}.Shouldnt be used in pure DRAINAGE or IMBIBITION.",
+ "TableCapillaryPressureHysteresis",
+ (mode == ModeIndexType::DRAINAGE) ? "DRAINAGE" : ((mode ==
+ ModeIndexType::IMBIBITION)
+ ? "IMBIBITION"
+ : "UNKNOWN")),
+ InputError );
+ }
+
+
+ }
+
+}
+void TableCapillaryPressureHysteresis::KernelWrapper::computeTwoPhaseWetting( const geos::integer ipWetting,
+ const geos::integer GEOS_UNUSED_PARAM( ipNonWetting ),
+ const arraySlice1d< const geos::real64,
+ compflow::USD_PHASE -
+ 1 > & phaseVolFraction,
+ const arraySlice1d< const geos::real64,
+ compflow::USD_PHASE
+ -
+ 1 > & phaseMaxHistoricalVolFraction,
+ const arraySlice1d< const geos::real64,
+ compflow::USD_PHASE
+ -
+ 1 > & phaseMinHistoricalVolFraction,
+ const arraySlice1d< geos::real64,
+ relperm::USD_RELPERM
+ - 2 > & phaseTrappedVolFrac,
+ arraySlice1d< geos::real64,
+ relperm::USD_RELPERM
+ -
+ 2 > const & phaseCapPressure,
+ arraySlice2d< geos::real64,
+ relperm::USD_RELPERM_DS
+ -
+ 2 > const & dPhaseCapPressure_dPhaseVolFrac,
+ ModeIndexType & mode,
+ arraySlice1d< geos::real64,
+ compflow::USD_PHASE - 1 > & phaseMode2PeakVolFraction ) const
+{
+ using TTP = ThreePhasePairPhaseType;
+
+ // Validate array sizes and indices before accessing
+ GEOS_ASSERT_MSG( ipWetting >= 0, "ipWetting must be non-negative" );
+ GEOS_ASSERT_MSG( static_cast< integer >(phaseVolFraction.size()) > ipWetting,
+ GEOS_FMT( "phaseVolFraction array too small: size={}, ipWetting={}. "
+ "This usually means the arrays haven't been properly resized. "
+ "Ensure resizeFields() has been called before using the KernelWrapper.",
+ phaseVolFraction.size(), ipWetting ));
+ GEOS_ASSERT_MSG( static_cast< integer >(phaseMaxHistoricalVolFraction.size()) > ipWetting,
+ GEOS_FMT( "phaseMaxHistoricalVolFraction array too small: size={}, ipWetting={}. "
+ "This usually means the arrays haven't been properly resized. "
+ "Ensure resizeFields() has been called before using the KernelWrapper.",
+ phaseMaxHistoricalVolFraction.size(), ipWetting ));
+ GEOS_ASSERT_MSG( static_cast< integer >(phaseMinHistoricalVolFraction.size()) > ipWetting,
+ GEOS_FMT( "phaseMinHistoricalVolFraction array too small: size={}, ipWetting={}. "
+ "This usually means the arrays haven't been properly resized. "
+ "Ensure resizeFields() has been called before using the KernelWrapper.",
+ phaseMinHistoricalVolFraction.size(), ipWetting ));
+ GEOS_ASSERT_MSG( static_cast< integer >(m_wettingNonWettingCapillaryPressureKernelWrappers.size()) >= 2,
+ GEOS_FMT( "m_wettingNonWettingCapillaryPressureKernelWrappers must have at least 2 elements, but got {}. "
+ "This usually means createAllTableKernelWrappers() failed to populate the arrays.",
+ m_wettingNonWettingCapillaryPressureKernelWrappers.size()));
+
+ // TEMPORARY: Disable scanning curves for testing convergence
+ // Define at function scope so it's accessible to both wetting and non-wetting phase code
+ constexpr bool ENABLE_SCANNING_CURVES = true;
+
+ // TEMPORARY: Force IMBIBITION mode for testing (overrides normal mode determination)
+ constexpr bool FORCE_IMBIBITION_MODE = false;
+
+ // TEMPORARY: Enable/disable Mode 4 (IMBIBITION_TO_DRAINAGE_FROM_SCANNING)
+ // When false, the code stays in Mode 2 and does not transition to Mode 4
+ constexpr bool ENABLE_MODE4 = false;
+
+ // Determine mode based on saturation condition and flow direction
+ // Use DRAINAGE when saturation is at or below minimum historical
+ // Use scanning curves when above minimum, detecting direction of change
+ bool const useDrainage = FORCE_IMBIBITION_MODE ? false :
+ (!m_phaseHasHysteresis[TTP::INTERMEDIATE_WETTING] ||
+ phaseVolFraction[ipWetting] <= phaseMinHistoricalVolFraction[ipWetting] + flowReversalBuffer);
+
+ //--- wetting cap pressure -- W/O or W/G two phase flow
+ // Use drainage curve when S <= S_min
+ // Use scanning curves when S > S_min, but detect if we're in secondary drainage
+ // DEBUG: Print mode for capillary pressure
+ // printf("CapPressure: mode=%d, S_w=%.6e, S_min=%.6e, S_max=%.6e, hasHyst=%d\n",
+ // static_cast(mode),
+ // phaseVolFraction[ipWetting],
+ // phaseMinHistoricalVolFraction[ipWetting],
+ // phaseMaxHistoricalVolFraction[ipWetting],
+ // static_cast(m_phaseHasHysteresis[TTP::INTERMEDIATE_WETTING]));
+
+ if( useDrainage )
+ {
+ // Use simple drainage curve (matching relative permeability)
+ mode = ModeIndexType::DRAINAGE;
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( phaseVolFraction[ipWetting],
+ m_wettingCurve.oppositeBoundPhaseVolFraction );
+ // printf("CapPressure: Using DRAINAGE curve (arrayIndex=0)\n");
+ GEOS_ASSERT_MSG( static_cast< integer >(m_wettingNonWettingCapillaryPressureKernelWrappers.size()) > ModeIndexType::DRAINAGE,
+ "Invalid array index for kernel wrapper access" );
+ computeBoundCapillaryPressure(
+ m_wettingNonWettingCapillaryPressureKernelWrappers[ModeIndexType::DRAINAGE],
+ phaseVolFraction[ipWetting],
+ phaseCapPressure[ipWetting],
+ dPhaseCapPressure_dPhaseVolFrac[ipWetting][ipWetting] );
+ }
+ else
+ {
+ // Use scanning curves - original conservative approach: only switch from pure states to scanning curves
+ // Scanning curve modes persist once set (no switching between DRAINAGE_TO_IMBIBITION and IMBIBITION_TO_DRAINAGE)
+
+ // If mode is already set to pure IMBIBITION, use it directly (for Pc bounds computation)
+ if( mode == ModeIndexType::IMBIBITION )
+ {
+ // Force pure imbibition mode - use the imbibition table directly
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( phaseVolFraction[ipWetting],
+ m_wettingCurve.oppositeBoundPhaseVolFraction );
+ GEOS_ASSERT_MSG( static_cast< integer >(m_wettingNonWettingCapillaryPressureKernelWrappers.size()) > ModeIndexType::IMBIBITION,
+ "Invalid array index for kernel wrapper access" );
+ computeBoundCapillaryPressure(
+ m_wettingNonWettingCapillaryPressureKernelWrappers[ModeIndexType::IMBIBITION],
+ phaseVolFraction[ipWetting],
+ phaseCapPressure[ipWetting],
+ dPhaseCapPressure_dPhaseVolFrac[ipWetting][ipWetting] );
+ return; // Exit early, don't use scanning curves
+ }
+
+ // If FORCE_IMBIBITION_MODE is enabled, override mode to IMBIBITION
+ if( FORCE_IMBIBITION_MODE )
+ {
+ mode = ModeIndexType::IMBIBITION;
+ }
+
+ // If scanning curves are disabled, reset any scanning curve modes back to pure modes
+ if( !ENABLE_SCANNING_CURVES )
+ {
+ if( mode == ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ mode == ModeIndexType::IMBIBITION_TO_DRAINAGE ||
+ mode == ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ // Reset to pure drainage or imbibition based on saturation
+ if( FORCE_IMBIBITION_MODE )
+ {
+ mode = ModeIndexType::IMBIBITION;
+ }
+ else
+ {
+ real64 const Smin = m_wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Smax = m_wettingCurve.drainageExtremaPhaseVolFraction;
+ real64 const Shy_min = (phaseMinHistoricalVolFraction[ipWetting] > Smin) ?
+ phaseMinHistoricalVolFraction[ipWetting] : Smin;
+ real64 const Shy_max = (phaseMaxHistoricalVolFraction[ipWetting] < Smax) ?
+ phaseMaxHistoricalVolFraction[ipWetting] : Smax;
+ real64 const currentS = phaseVolFraction[ipWetting];
+
+ if( currentS <= Shy_min + flowReversalBuffer )
+ {
+ mode = ModeIndexType::DRAINAGE;
+ }
+ else if( currentS >= Shy_max - flowReversalBuffer )
+ {
+ mode = ModeIndexType::IMBIBITION;
+ }
+ else
+ {
+ // Default to drainage if in between
+ mode = ModeIndexType::DRAINAGE;
+ }
+ }
+ }
+ }
+
+ bool justSwitchedToMode2 = false;
+ if( ENABLE_SCANNING_CURVES && (mode == ModeIndexType::DRAINAGE || mode == ModeIndexType::IMBIBITION))
+ {
+ // Transitioning from a pure state to a scanning curve.
+ // The previous mode tells us the direction of the reversal:
+ // - From DRAINAGE: saturation is now increasing → DRAINAGE_TO_IMBIBITION (Mode 2)
+ // - From IMBIBITION: saturation is now decreasing → IMBIBITION_TO_DRAINAGE (Mode 3)
+ if( mode == ModeIndexType::DRAINAGE )
+ {
+ mode = ModeIndexType::DRAINAGE_TO_IMBIBITION;
+ justSwitchedToMode2 = true;
+ }
+ else
+ {
+ mode = ModeIndexType::IMBIBITION_TO_DRAINAGE;
+ // Reset Mode 2 peak when leaving imbibition
+ if( phaseMode2PeakVolFraction[ipWetting] > 0.0 )
+ {
+ phaseMode2PeakVolFraction[ipWetting] = 0.0;
+ }
+ }
+ }
+ // Mode 2 peak is now tracked explicitly at end of timestep in saveConvergedPhaseVolFractionState()
+ // No need to update it during Newton iterations - use constant value from previous timestep
+ // This prevents oscillations during Newton solve from affecting the peak value
+ // Check for transition from DRAINAGE_TO_IMBIBITION to drainage (departing from scanning curve)
+ // Mode 4: Switch when saturation decreases from the peak reached during Mode 2
+ // In Mode 2, saturation increases from Shy_min (reversal point) towards Mode2_peak
+ // Once saturation starts decreasing from Mode2_peak by at least 1e-4, switch to Mode 4
+ // IMPORTANT: Only check for Mode 4 if we were already in Mode 2 (not just switched from Mode 0)
+ // This prevents immediate Mode 0 -> Mode 2 -> Mode 4 transition within a single Newton iteration
+ // TEMPORARY: Disable scanning curves for testing convergence
+ if( ENABLE_MODE4 && ENABLE_SCANNING_CURVES && mode == ModeIndexType::DRAINAGE_TO_IMBIBITION && !justSwitchedToMode2 )
+ {
+ real64 const currentS = phaseVolFraction[ipWetting];
+ real64 const Mode2_peak = phaseMode2PeakVolFraction[ipWetting];
+ // Use same approach as other mode switches: small buffer + mode persistence
+ // Similar to Mode 0 -> Mode 2: use flowReversalBuffer (1e-12) for consistency
+ // Mode 4 will persist once set, preventing oscillation-induced switching
+ // However, we need a slightly larger buffer than 1e-12 because:
+ // 1. The peak is a dynamic value that was just reached
+ // 2. Saturation can oscillate around the peak during Newton iterations
+ // Use a relative buffer: 0.01% of the peak value, with a minimum of 1e-4
+ // This is still much smaller than before but provides some protection against numerical noise
+ real64 const relativeBuffer = 0.0001 * Mode2_peak; // 0.01% of peak
+ real64 const absoluteBuffer = 1e-4; // Minimum absolute buffer (same as original)
+ real64 const decreaseBuffer = LvArray::math::max( relativeBuffer, absoluteBuffer );
+ // Valid range for Mode 4 switching: between min and max historical saturations
+ real64 const Smin = m_wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Smax = m_wettingCurve.drainageExtremaPhaseVolFraction;
+ real64 const S_test_min = (phaseMinHistoricalVolFraction[ipWetting] > Smin) ?
+ phaseMinHistoricalVolFraction[ipWetting] : Smin;
+ real64 const S_test_max = (phaseMaxHistoricalVolFraction[ipWetting] < Smax) ?
+ phaseMaxHistoricalVolFraction[ipWetting] : Smax;
+
+ // Check: saturation must have decreased from the Mode 2 peak
+ // Only switch to Mode 4 if currentS < Mode2_peak - decreaseBuffer
+ // Also ensure Mode2_peak is valid (non-zero, meaning we've tracked a peak)
+ // And current saturation is within valid historical range
+ // Once Mode 4 is set, it persists (like Mode 2), preventing oscillation-induced switching
+ bool saturationHasDecreased = (Mode2_peak > 0.0 && currentS < Mode2_peak - decreaseBuffer);
+
+ if( saturationHasDecreased &&
+ currentS >= S_test_min &&
+ currentS <= S_test_max )
+ {
+ mode = ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING;
+ }
+ // Otherwise, keep Mode 2 (saturation still increasing or hasn't decreased enough from peak)
+ // Mode 2 persists once set, similar to how Mode 0 persists when S <= S_min + flowReversalBuffer
+ }
+ // IMBIBITION_TO_DRAINAGE_FROM_SCANNING mode persists once set
+
+ // If scanning curves are disabled, use pure drainage/imbibition curves
+ if( !ENABLE_SCANNING_CURVES &&
+ (mode == ModeIndexType::DRAINAGE || mode == ModeIndexType::IMBIBITION))
+ {
+ // Use pure drainage or imbibition curve
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( phaseVolFraction[ipWetting],
+ m_wettingCurve.oppositeBoundPhaseVolFraction );
+ GEOS_ASSERT_MSG( static_cast< integer >(m_wettingNonWettingCapillaryPressureKernelWrappers.size()) > mode,
+ "Invalid array index for kernel wrapper access" );
+ computeBoundCapillaryPressure(
+ m_wettingNonWettingCapillaryPressureKernelWrappers[mode],
+ phaseVolFraction[ipWetting],
+ phaseCapPressure[ipWetting],
+ dPhaseCapPressure_dPhaseVolFrac[ipWetting][ipWetting] );
+ }
+ else
+ {
+ // Use scanning curves
+ // printf("CapPressure: Using scanning curve (mode=%d)\n", static_cast(mode));
+ computeImbibitionWettingCapillaryPressure( m_wettingNonWettingCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_landParam[ipWetting],
+ phaseVolFraction[ipWetting],
+ phaseMinHistoricalVolFraction[ipWetting],
+ phaseMaxHistoricalVolFraction[ipWetting],
+ phaseMode2PeakVolFraction[ipWetting],
+ phaseTrappedVolFrac[ipWetting],
+ phaseCapPressure[ipWetting],
+ dPhaseCapPressure_dPhaseVolFrac[ipWetting][ipWetting],
+ mode );
+ }
+ }
+
+// trapped vol fraction
+ if( mode == ModeIndexType::DRAINAGE || mode == ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ mode == ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+
+
+
+ real64 const Smin = m_wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Shy = (phaseMinHistoricalVolFraction[ipWetting] < Smin)
+ ? phaseMinHistoricalVolFraction[ipWetting]
+ : Smin;
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, Shy,
+ m_landParam[ipWetting],
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipWetting] );
+
+
+ //keep the same Land coeff as two phase only
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve.toNonWetting(), Shy,
+ m_landParam[ipWetting],
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipWetting] );
+
+
+
+ }
+ else if( mode == ModeIndexType::IMBIBITION || mode == ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+
+ real64 const Smax = m_wettingCurve.imbibitionExtremaPhaseVolFraction;
+ real64 const Shy = (phaseMaxHistoricalVolFraction[ipWetting] < Smax)
+ ? phaseMaxHistoricalVolFraction[ipWetting]
+ : Smax;
+ real64 Scrt = 0.0;
+ //TODO (jacques) check if still accurate
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve,
+ Shy,
+ m_landParam[ipWetting],
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ Scrt );
+
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipWetting] );
+
+ //keep the same Land coeff as two phase only
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve.toNonWetting(), Shy,
+ m_landParam[ipWetting],
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipWetting] );
+
+ }
+
+}
+
+void TableCapillaryPressureHysteresis::KernelWrapper::computeTwoPhaseNonWetting( const geos::integer ipWetting,
+ const geos::integer ipNonWetting,
+ const arraySlice1d< const geos::real64,
+ compflow::USD_PHASE -
+ 1 > & phaseVolFraction,
+ const arraySlice1d< const geos::real64,
+ compflow::USD_PHASE
+ -
+ 1 > & phaseMaxHistoricalVolFraction,
+ const arraySlice1d< const geos::real64,
+ compflow::USD_PHASE
+ -
+ 1 > & phaseMinHistoricalVolFraction,
+ const arraySlice1d< geos::real64,
+ relperm::USD_RELPERM
+ -
+ 2 > & phaseTrappedVolFrac,
+ arraySlice1d< geos::real64,
+ relperm::USD_RELPERM
+ -
+ 2 > const & phaseCapPressure,
+ arraySlice2d< geos::real64,
+ relperm::USD_RELPERM_DS
+ -
+ 2 > const & dPhaseCapPressure_dPhaseVolFrac,
+ ModeIndexType & mode ) const
+{
+ using TTP = ThreePhasePairPhaseType;
+
+ // TEMPORARY: Disable scanning curves for testing convergence
+ // Define at function scope so it's accessible throughout this function
+ constexpr bool ENABLE_SCANNING_CURVES = true;
+
+ // TEMPORARY: Force IMBIBITION mode for testing (overrides normal mode determination)
+ constexpr bool FORCE_IMBIBITION_MODE = false;
+
+ //update state
+ // TODO check if we can get rid of DRAINAGE_TO_IMBIBITION && IMBIBITION_TO_DRAINAGE
+ if( mode == ModeIndexType::DRAINAGE_TO_IMBIBITION &&
+ phaseVolFraction[ipNonWetting] >= phaseMaxHistoricalVolFraction[ipNonWetting] + flowReversalBuffer )
+ mode = ModeIndexType::DRAINAGE;
+ if( mode == ModeIndexType::IMBIBITION_TO_DRAINAGE &&
+ phaseVolFraction[ipWetting] <= phaseMinHistoricalVolFraction[ipNonWetting] + flowReversalBuffer )
+ mode = ModeIndexType::IMBIBITION;
+
+
+
+ // If scanning curves are disabled, reset any scanning curve modes back to pure modes
+ if( !ENABLE_SCANNING_CURVES )
+ {
+ if( mode == ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ mode == ModeIndexType::IMBIBITION_TO_DRAINAGE ||
+ mode == ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ // Reset to pure drainage or imbibition based on saturation
+ if( FORCE_IMBIBITION_MODE )
+ {
+ mode = ModeIndexType::IMBIBITION;
+ }
+ else
+ {
+ if( phaseVolFraction[ipNonWetting] <= phaseMinHistoricalVolFraction[ipNonWetting] + flowReversalBuffer )
+ {
+ mode = ModeIndexType::DRAINAGE;
+ }
+ else if( phaseVolFraction[ipNonWetting] >= phaseMaxHistoricalVolFraction[ipNonWetting] - flowReversalBuffer )
+ {
+ mode = ModeIndexType::IMBIBITION;
+ }
+ else
+ {
+ // Default to drainage if in between
+ mode = ModeIndexType::DRAINAGE;
+ }
+ }
+ }
+ }
+
+ // Force IMBIBITION mode if flag is set (overrides all other logic)
+ if( FORCE_IMBIBITION_MODE )
+ {
+ mode = ModeIndexType::IMBIBITION;
+ }
+
+ if( ENABLE_SCANNING_CURVES && (mode == ModeIndexType::DRAINAGE || mode == ModeIndexType::IMBIBITION))
+ {
+ // Handle transitions from pure states to scanning curves
+ // If current saturation is significantly above min historical, we're in imbibition
+ if( phaseVolFraction[ipNonWetting] > phaseMinHistoricalVolFraction[ipNonWetting] + flowReversalBuffer )
+ {
+ if( mode == ModeIndexType::DRAINAGE )
+ {
+ mode = ModeIndexType::DRAINAGE_TO_IMBIBITION;
+ }
+ }
+ // If current saturation is significantly below max historical, we're in drainage
+ else if( phaseVolFraction[ipNonWetting] < phaseMaxHistoricalVolFraction[ipNonWetting] - flowReversalBuffer )
+ {
+ if( mode == ModeIndexType::IMBIBITION )
+ {
+ mode = ModeIndexType::IMBIBITION_TO_DRAINAGE;
+ }
+ }
+ }
+ // Mode 4 switching is only implemented for wetting phase, not for non-wetting phase
+ // Scanning curve modes persist - no switching between DRAINAGE_TO_IMBIBITION and IMBIBITION_TO_DRAINAGE
+
+ // Use simple drainage/imbibition curves when:
+ // 1. No hysteresis enabled, OR
+ // 2. We're in pure DRAINAGE mode (use drainage curve), OR
+ // 3. We're in pure IMBIBITION mode (use imbibition curve)
+ // Use scanning curves only during transitions (DRAINAGE_TO_IMBIBITION or IMBIBITION_TO_DRAINAGE)
+ if( !m_phaseHasHysteresis[TTP::INTERMEDIATE_NONWETTING] ||
+ mode == ModeIndexType::DRAINAGE ||
+ mode == ModeIndexType::IMBIBITION )
+ {
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( phaseVolFraction[ipNonWetting],
+ (mode == ModeIndexType::DRAINAGE)
+ ? m_nonWettingCurve.drainageExtremaPhaseVolFraction
+ : m_nonWettingCurve.imbibitionExtremaPhaseVolFraction );
+ // Ensure mode is a valid array index (0 or 1)
+ integer const arrayIndex = (mode == ModeIndexType::DRAINAGE) ? ModeIndexType::DRAINAGE : ModeIndexType::IMBIBITION;
+ GEOS_ASSERT_MSG( arrayIndex >= 0 && arrayIndex < static_cast< integer >(m_wettingNonWettingCapillaryPressureKernelWrappers.size()),
+ "Invalid array index for kernel wrapper access" );
+ computeBoundCapillaryPressure(
+ m_wettingNonWettingCapillaryPressureKernelWrappers[arrayIndex],
+ phaseVolFraction[ipNonWetting],
+ phaseCapPressure[ipNonWetting],
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting] );
+ // when pc is on the gas phase, we need to multiply user input by -1
+ // because CompositionalMultiphaseFVM does: pres_gas = pres_oil - pc_og, so we need a negative pc_og
+ phaseCapPressure[ipNonWetting] *= -1;
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting] *= -1;
+
+ }
+ else
+ {
+ // We're in a transition state (DRAINAGE_TO_IMBIBITION or IMBIBITION_TO_DRAINAGE)
+ // Use scanning curves (unless disabled)
+ if( !ENABLE_SCANNING_CURVES )
+ {
+ // Scanning curves disabled - use pure drainage/imbibition based on current mode
+ // This should not happen if reset logic worked correctly, but handle it anyway
+ if( mode == ModeIndexType::DRAINAGE || mode == ModeIndexType::IMBIBITION )
+ {
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( phaseVolFraction[ipNonWetting],
+ (mode == ModeIndexType::DRAINAGE)
+ ? m_nonWettingCurve.drainageExtremaPhaseVolFraction
+ : m_nonWettingCurve.imbibitionExtremaPhaseVolFraction );
+ integer const arrayIndex = (mode == ModeIndexType::DRAINAGE) ? ModeIndexType::DRAINAGE : ModeIndexType::IMBIBITION;
+ GEOS_ASSERT_MSG( arrayIndex >= 0 && arrayIndex < static_cast< integer >(m_wettingNonWettingCapillaryPressureKernelWrappers.size()),
+ "Invalid array index for kernel wrapper access" );
+ computeBoundCapillaryPressure(
+ m_wettingNonWettingCapillaryPressureKernelWrappers[arrayIndex],
+ phaseVolFraction[ipNonWetting],
+ phaseCapPressure[ipNonWetting],
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting] );
+ phaseCapPressure[ipNonWetting] *= -1;
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting] *= -1;
+ }
+ else
+ {
+ mode = ModeIndexType::DRAINAGE;
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( phaseVolFraction[ipNonWetting],
+ m_nonWettingCurve.drainageExtremaPhaseVolFraction );
+ computeBoundCapillaryPressure(
+ m_wettingNonWettingCapillaryPressureKernelWrappers[ModeIndexType::DRAINAGE],
+ phaseVolFraction[ipNonWetting],
+ phaseCapPressure[ipNonWetting],
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting] );
+ phaseCapPressure[ipNonWetting] *= -1;
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting] *= -1;
+ }
+ }
+ else
+ {
+ // Use scanning curves
+
+ computeImbibitionNonWettingCapillaryPressure( m_wettingNonWettingCapillaryPressureKernelWrappers,
+ m_nonWettingCurve,
+ m_landParam[ipNonWetting],
+ phaseVolFraction[ipNonWetting],
+ phaseMaxHistoricalVolFraction[ipNonWetting],
+ phaseTrappedVolFrac[ipNonWetting],
+ phaseCapPressure[ipNonWetting],
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting],
+ mode );
+
+ // when pc is on the gas phase, we need to multiply user input by -1
+ // because CompositionalMultiphaseFVM does: pres_gas = pres_oil - pc_og, so we need a negative pc_og
+ phaseCapPressure[ipNonWetting] *= -1;
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting] *= -1;
+ }
+ }
+
+// trapped vol fraction
+ if( mode == ModeIndexType::DRAINAGE || mode == ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ mode == ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+
+ {
+ real64 const Smax = m_nonWettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Shy = (phaseMaxHistoricalVolFraction[ipNonWetting] > Smax)
+ ? phaseMaxHistoricalVolFraction[ipNonWetting]
+ : Smax;
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve, Shy,
+ m_landParam[ipNonWetting],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipNonWetting] );
+
+ //keep the same Land coeff as two phase only
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve.toWetting(), Shy,
+ m_landParam[ipNonWetting],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipNonWetting] );
+ }
+ }
+ else if( mode == ModeIndexType::IMBIBITION || mode == ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+
+ {
+ real64 const Smin = m_nonWettingCurve.imbibitionExtremaPhaseVolFraction;;
+ real64 const Shy = (phaseMinHistoricalVolFraction[ipNonWetting] > Smin)
+ ? phaseMinHistoricalVolFraction[ipNonWetting]
+ : Smin;
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve, Shy,
+ m_landParam[ipNonWetting],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipNonWetting] );
+
+ //keep the same Land coeff as two phase only
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve.toWetting(), Shy,
+ m_landParam[ipNonWetting],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipNonWetting] );
+ }
+ }
+
+
+}
+
+void TableCapillaryPressureHysteresis::KernelWrapper::computeThreePhase( const geos::integer ipWetting,
+ const geos::integer GEOS_UNUSED_PARAM( ipInter ),
+ const geos::integer ipNonWetting,
+ const arraySlice1d< const geos::real64,
+ compflow::USD_PHASE -
+ 1 > & phaseVolFraction,
+ const arraySlice1d< const geos::real64,
+ compflow::USD_PHASE
+ -
+ 1 > & phaseMaxHistoricalVolFraction,
+ const arraySlice1d< const geos::real64,
+ compflow::USD_PHASE
+ -
+ 1 > & phaseMinHistoricalVolFraction,
+ const arraySlice1d< geos::real64,
+ relperm::USD_RELPERM
+ - 2 > & phaseTrappedVolFrac,
+ const arraySlice1d< geos::real64,
+ relperm::USD_RELPERM -
+ 2 > & phaseCapPressure,
+ const arraySlice2d< geos::real64,
+ relperm::USD_RELPERM_DS
+ -
+ 2 > & dPhaseCapPressure_dPhaseVolFrac,
+ ModeIndexType & mode,
+ arraySlice1d< geos::real64,
+ compflow::USD_PHASE
+ -
+ 1 > & phaseMode2PeakVolFraction ) const
+{
+
+
+ LvArray::forValuesInSlice( dPhaseCapPressure_dPhaseVolFrac, []( real64 & val ) { val = 0.0; } );
+ using TTP = ThreePhasePairPhaseType;
+
+ // -- wetting curve if drainage only
+ constexpr bool ENABLE_COMPUTE_BRANCH_DEBUG = false;
+ bool usePureCurve = !m_phaseHasHysteresis[TTP::INTERMEDIATE_WETTING] ||
+ (mode == ModeIndexType::DRAINAGE &&
+ phaseVolFraction[ipWetting] <= phaseMinHistoricalVolFraction[ipWetting] + flowReversalBuffer) ||
+ (mode == ModeIndexType::IMBIBITION &&
+ phaseVolFraction[ipWetting] >= phaseMaxHistoricalVolFraction[ipWetting] + flowReversalBuffer);
+
+ if constexpr (ENABLE_COMPUTE_BRANCH_DEBUG) {
+ if( mode == ModeIndexType::DRAINAGE || mode == ModeIndexType::IMBIBITION )
+ {
+ std::cout << "[COMPUTE_BRANCH_DEBUG] Two-phase wetting, mode=" << (mode == ModeIndexType::DRAINAGE ? "DRAINAGE" : "IMBIBITION")
+ << ", S=" << phaseVolFraction[ipWetting]
+ << ", S_min=" << phaseMinHistoricalVolFraction[ipWetting]
+ << ", S_max=" << phaseMaxHistoricalVolFraction[ipWetting]
+ << ", usePureCurve=" << (usePureCurve ? "true" : "false")
+ << ", hasHysteresis=" << m_phaseHasHysteresis[TTP::INTERMEDIATE_WETTING] << std::endl;
+ }
+ }
+
+ if( usePureCurve )
+ {
+ // water-oil capillary pressure
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( phaseVolFraction[ipWetting],
+ m_wettingCurve.oppositeBoundPhaseVolFraction );
+ constexpr bool ENABLE_COMPUTE_TABLE_DEBUG = false;
+ real64 S_before = phaseVolFraction[ipWetting];
+ real64 dPc_dS_before = dPhaseCapPressure_dPhaseVolFrac[ipWetting][ipWetting];
+ integer const tableIndex = static_cast< integer >(mode);
+ if constexpr (ENABLE_COMPUTE_TABLE_DEBUG) {
+ std::cout << "[COMPUTE_TABLE_DEBUG_TCH] Forward table lookup: mode=" << (mode == ModeIndexType::DRAINAGE ? "DRAINAGE" : "IMBIBITION")
+ << ", tableIndex=" << tableIndex
+ << ", S=" << S_before
+ << ", wrapper.size()=" << m_wettingIntermediateCapillaryPressureKernelWrappers.size() << std::endl;
+ }
+ phaseCapPressure[ipWetting] =
+ m_wettingIntermediateCapillaryPressureKernelWrappers[mode].compute(
+ &(phaseVolFraction)[ipWetting],
+ &(dPhaseCapPressure_dPhaseVolFrac)[ipWetting][ipWetting] );
+ real64 dPc_dS_after = dPhaseCapPressure_dPhaseVolFrac[ipWetting][ipWetting];
+ if constexpr (ENABLE_COMPUTE_TABLE_DEBUG) {
+ std::cout << "[COMPUTE_TABLE_DEBUG_TCH] After table.compute: Pc=" << phaseCapPressure[ipWetting]
+ << ", dPc_dS_before=" << dPc_dS_before
+ << ", dPc_dS_after=" << dPc_dS_after << std::endl;
+ }
+ }
+ else
+ {
+ // We're in a scanning curve state - preserve the mode if already set, otherwise determine from position
+ if( mode != ModeIndexType::DRAINAGE_TO_IMBIBITION &&
+ mode != ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // Starting from a pure state - determine initial scanning curve direction
+ mode = (mode == ModeIndexType::DRAINAGE) ? ModeIndexType::DRAINAGE_TO_IMBIBITION
+ : ModeIndexType::IMBIBITION_TO_DRAINAGE;
+ }
+ computeImbibitionWettingCapillaryPressure( m_wettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipWetting],
+ phaseVolFraction[ipWetting],
+ phaseMinHistoricalVolFraction[ipWetting],
+ phaseMaxHistoricalVolFraction[ipWetting],
+ phaseMode2PeakVolFraction[ipWetting],
+ phaseTrappedVolFrac[ipWetting],
+ phaseCapPressure[ipWetting],
+ dPhaseCapPressure_dPhaseVolFrac[ipWetting][ipWetting],
+ mode );
+
+
+ }
+
+
+ // -- non-wetting cure if drainage only
+ // gas-oil capillary pressure
+ if( !m_phaseHasHysteresis[TTP::INTERMEDIATE_NONWETTING] ||
+ (mode == ModeIndexType::DRAINAGE &&
+ phaseVolFraction[ipNonWetting] >= phaseMaxHistoricalVolFraction[ipNonWetting] + flowReversalBuffer) ||
+ (mode == ModeIndexType::IMBIBITION &&
+ phaseVolFraction[ipNonWetting] <= phaseMinHistoricalVolFraction[ipNonWetting] + flowReversalBuffer))
+ {
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( phaseVolFraction[ipNonWetting],
+ (mode == ModeIndexType::DRAINAGE)
+ ? m_nonWettingCurve.drainageExtremaPhaseVolFraction
+ : m_nonWettingCurve.imbibitionExtremaPhaseVolFraction );
+ phaseCapPressure[ipNonWetting] =
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers[mode].compute(
+ &(phaseVolFraction)[ipNonWetting],
+ &(dPhaseCapPressure_dPhaseVolFrac)[ipNonWetting][ipNonWetting] );
+
+
+ // when pc is on the gas phase, we need to multiply user input by -1
+ // because CompositionalMultiphaseFVM does: pres_gas = pres_oil - pc_og, so we need a negative pc_og
+ phaseCapPressure[ipNonWetting] *= -1;
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting] *= -1;
+ }
+ else
+ {
+ // We're in a scanning curve state - preserve the mode if already set, otherwise determine from position
+ if( mode != ModeIndexType::DRAINAGE_TO_IMBIBITION &&
+ mode != ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // Starting from a pure state - determine initial scanning curve direction
+ mode = (mode == ModeIndexType::DRAINAGE) ? ModeIndexType::DRAINAGE_TO_IMBIBITION
+ : ModeIndexType::IMBIBITION_TO_DRAINAGE;
+ }
+
+ computeImbibitionNonWettingCapillaryPressure( m_nonWettingIntermediateCapillaryPressureKernelWrappers,
+ m_nonWettingCurve,
+ m_wettingCurve,
+ m_landParam[ipNonWetting],
+ phaseVolFraction[ipNonWetting],
+ phaseMinHistoricalVolFraction[ipNonWetting],
+ phaseTrappedVolFrac[ipNonWetting],
+ phaseCapPressure[ipNonWetting],
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting],
+ mode );
+ // when pc is on the gas phase, we need to multiply user input by -1
+ // because CompositionalMultiphaseFVM does: pres_gas = pres_oil - pc_og, so we need a negative pc_og
+ phaseCapPressure[ipNonWetting] *= -1;
+ dPhaseCapPressure_dPhaseVolFrac[ipNonWetting][ipNonWetting] *= -1;
+
+ //update trapped fraction
+ if( mode == ModeIndexType::DRAINAGE || mode == ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ mode == ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+
+
+ {
+ real64 const Smin = m_wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Shy = (phaseMinHistoricalVolFraction[ipWetting] < Smin)
+ ? phaseMinHistoricalVolFraction[ipWetting]
+ : Smin;
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, Shy,
+ m_landParam[ipWetting],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipWetting] );
+ }
+
+ {
+ real64 const Smax = m_nonWettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Shy = (phaseMaxHistoricalVolFraction[ipNonWetting] > Smax)
+ ? phaseMaxHistoricalVolFraction[ipNonWetting]
+ : Smax;
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve, Shy,
+ m_landParam[ipNonWetting],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipNonWetting] );
+ }
+ }
+ else if( mode == ModeIndexType::IMBIBITION || mode == ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ {
+ real64 const Smax = m_wettingCurve.imbibitionExtremaPhaseVolFraction;
+ real64 const Shy = (phaseMaxHistoricalVolFraction[ipWetting] < Smax)
+ ? phaseMaxHistoricalVolFraction[ipWetting]
+ : Smax;
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, Shy,
+ m_landParam[ipWetting],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipWetting] );
+ }
+
+ {
+ real64 const Smin = m_nonWettingCurve.imbibitionExtremaPhaseVolFraction;;
+ real64 const Shy = (phaseMinHistoricalVolFraction[ipNonWetting] > Smin)
+ ? phaseMinHistoricalVolFraction[ipNonWetting]
+ : Smin;
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve, Shy,
+ m_landParam[ipNonWetting],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipNonWetting] );
+ }
+ }
+
+
+ }
+
+
+}
+
+
+void
+TableCapillaryPressureHysteresis::KernelWrapper::computeImbibitionNonWettingCapillaryPressure(
+ const arrayView1d< const TableFunction::KernelWrapper > & nonWettingKernelWrapper,
+ const KilloughHysteresis::HysteresisCurve & nonWettingCurve,
+ const KilloughHysteresis::HysteresisCurve & wettingCurve,
+ const geos::real64 & landParam,
+ const geos::real64 & phaseVolFraction,
+ const geos::real64 & phaseMaxHistoricalVolFraction,
+ geos::real64 & phaseTrappedVolFrac,
+ geos::real64 & phaseCapPressure,
+ geos::real64 & dPhaseCapPressure_dPhaseVolFrac,
+ const ModeIndexType & mode ) const
+{
+ GEOS_ASSERT( !nonWettingCurve.isWetting());
+ real64 const S = phaseVolFraction;
+ real64 const Smii = nonWettingCurve.imbibitionExtremaPhaseVolFraction;
+ real64 const Smid = nonWettingCurve.drainageExtremaPhaseVolFraction;
+ real64 const Smax = nonWettingCurve.oppositeBoundPhaseVolFraction;
+
+ GEOS_UNUSED_VAR( Smii, Smid );
+
+// if( S >= Smax )
+// {
+// //above accessible range
+// phaseCapPressure = CAP_INF;
+// dPhaseCapPressure_dPhaseVolFrac = CAP_INF_DERIV;
+// }
+// else if( S <= Smid )
+// {
+// //below accessible range
+// phaseCapPressure = -CAP_INF;
+// dPhaseCapPressure_dPhaseVolFrac = CAP_INF_DERIV;
+// }
+// else
+ {
+ //drainage to imbibition
+ real64 dpci_dS, dpcd_dS;
+ real64 const pci = nonWettingKernelWrapper[ModeIndexType::IMBIBITION].compute( &S, &dpci_dS );
+ real64 const pcd = nonWettingKernelWrapper[ModeIndexType::DRAINAGE].compute( &S, &dpcd_dS );
+
+ // Step 1: get the trapped from wetting data
+ real64 const Shy = (phaseMaxHistoricalVolFraction < Smax) ? phaseMaxHistoricalVolFraction : Smax;
+
+ //drainage to imbibition
+ if( mode == ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( nonWettingCurve, Shy, landParam,
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+
+ real64 const E = m_killoughCurvatureParamCapPres;
+
+ //Set 2. compute F as in (EQ 34.21) F = (1/(Shy-S+E)-1/E) / (1/(Shy - Sgcr +E)-1/E)
+ real64 F = (1. / (Shy - S + E) - 1. / E) / (1. / (Shy - Scrt + E) - 1. / E);
+ //force bound
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ //Step 3. compute dF_dS
+ real64 dF_dS = (1. / (S * S)) / (1. / (Shy - Scrt + E) - 1. / E);
+
+ //Step 4. Eventually assemble everything following (EQ. 34.20)
+ phaseCapPressure = pcd + F * (pci - pcd);
+ dPhaseCapPressure_dPhaseVolFrac = dpci_dS + F * (dpci_dS - dpcd_dS);
+ dPhaseCapPressure_dPhaseVolFrac += dF_dS * (pci - pcd);
+
+ //update trapped fraction
+ phaseTrappedVolFrac = LvArray::math::min( Scrt, S );
+
+ }
+ //imbibition to drainage
+ else if( mode == ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( wettingCurve, Shy, landParam,
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ real64 Sgma = 1. - Scrt - m_phaseIntermediateMinVolFraction;
+
+ real64 const E = m_killoughCurvatureParamCapPres;
+
+ //Set 2. compute F as in (EQ 34.21) F = (1/(Shy-S+E)-1/E) / (1/(Shy - Sgcr +E)-1/E)
+ real64 F = (1. / (S - Shy + E) - 1. / E) / (1. / (Sgma - Shy + E) - 1. / E);
+ //force bound
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ //Step 3. compute dF_dS
+ real64 dF_dS = (-1. / (S * S)) / (1. / (Shy - Scrt + E) - 1. / E);
+
+ //Step 4. Eventually assemble everything following (EQ. 34.20)
+ phaseCapPressure = pci + F * (pcd - pci);
+ dPhaseCapPressure_dPhaseVolFrac = dpcd_dS + F * (dpcd_dS - dpci_dS);
+ dPhaseCapPressure_dPhaseVolFrac += dF_dS * (pcd - pci);
+ }
+ else
+ {
+ GEOS_THROW( GEOS_FMT( "{}: State is {}.Shouldnt be used in pure DRAINAGE or IMBIBITION.",
+ "TableCapillaryPressureHysteresis",
+ (mode == ModeIndexType::DRAINAGE) ? "DRAINAGE" : ((mode ==
+ ModeIndexType::IMBIBITION)
+ ? "IMBIBITION"
+ : "UNKNOWN")),
+ InputError );
+ }
+
+
+ }
+}
+
+
+void
+TableCapillaryPressureHysteresis::KernelWrapper::computeImbibitionNonWettingCapillaryPressure(
+ const arrayView1d< const TableFunction::KernelWrapper > & nonWettingKernelWrapper,
+ const KilloughHysteresis::HysteresisCurve & nonWettingCurve,
+ const geos::real64 & landParam,
+ const geos::real64 & phaseVolFraction,
+ const geos::real64 & phaseMaxHistoricalVolFraction,
+ geos::real64 & phaseTrappedVolFrac,
+ geos::real64 & phaseCapPressure,
+ geos::real64 & dPhaseCapPressure_dPhaseVolFrac,
+ const ModeIndexType & mode ) const
+{
+
+ GEOS_ASSERT( !nonWettingCurve.isWetting());
+ real64 const S = phaseVolFraction;
+ real64 const Smii = nonWettingCurve.imbibitionExtremaPhaseVolFraction;
+ real64 const Smid = nonWettingCurve.drainageExtremaPhaseVolFraction;
+ real64 const Smax = nonWettingCurve.oppositeBoundPhaseVolFraction;
+
+ GEOS_UNUSED_VAR( Smii, Smid );
+
+// if( S >= Smax )
+// {
+// //above accessible range
+// phaseCapPressure = CAP_INF;
+// dPhaseCapPressure_dPhaseVolFrac = CAP_INF_DERIV;
+// }
+// else if( S <= Smid )
+// {
+// //below accessible range
+// phaseCapPressure = -CAP_INF;
+// dPhaseCapPressure_dPhaseVolFrac = CAP_INF_DERIV;
+// }
+// else
+ {
+ //drainage to imbibition
+ real64 dpci_dS, dpcd_dS;
+ real64 const pci = nonWettingKernelWrapper[ModeIndexType::IMBIBITION].compute( &S, &dpci_dS );
+ real64 const pcd = nonWettingKernelWrapper[ModeIndexType::DRAINAGE].compute( &S, &dpcd_dS );
+
+ // Step 1: get the trapped from wetting data
+ real64 const Shy = (phaseMaxHistoricalVolFraction < Smax) ? phaseMaxHistoricalVolFraction : Smax;
+
+ //drainage to imbibition
+ if( mode == ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( nonWettingCurve, Shy, landParam,
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+
+ real64 const E = m_killoughCurvatureParamCapPres;
+
+ //Set 2. compute F as in (EQ 34.21) F = (1/(Shy-S+E)-1/E) / (1/(Shy - Sgcr +E)-1/E)
+ real64 F = (1. / (Shy - S + E) - 1. / E) / (1. / (Shy - Scrt + E) - 1. / E);
+ //force bound
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ //Step 3. compute dF_dS
+ real64 dF_dS = (1. / (S * S)) / (1. / (Shy - Scrt + E) - 1. / E);
+
+ //Step 4. Eventually assemble everything following (EQ. 34.20)
+ phaseCapPressure = pcd + F * (pci - pcd);
+ dPhaseCapPressure_dPhaseVolFrac = dpci_dS + F * (dpci_dS - dpcd_dS);
+ dPhaseCapPressure_dPhaseVolFrac += dF_dS * (pci - pcd);
+
+ //update trapped fraction
+ phaseTrappedVolFrac = LvArray::math::min( Scrt, S );
+
+ }
+ //imbibition to drainage
+ else if( mode == ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( nonWettingCurve, Shy, landParam,
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ real64 Sgma = 1. - (1. - Scrt);
+
+ real64 const E = m_killoughCurvatureParamCapPres;
+
+ //Set 2. compute F as in (EQ 34.21) F = (1/(Shy-S+E)-1/E) / (1/(Shy - Sgcr +E)-1/E)
+ real64 F = (1. / (S - Shy + E) - 1. / E) / (1. / (Sgma - Shy + E) - 1. / E);
+ //force bound
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ //Step 3. compute dF_dS
+ real64 dF_dS = (-1. / (S * S)) / (1. / (Shy - Scrt + E) - 1. / E);
+
+ //Step 4. Eventually assemble everything following (EQ. 34.20)
+ phaseCapPressure = pci + F * (pcd - pci);
+ dPhaseCapPressure_dPhaseVolFrac = dpcd_dS + F * (dpcd_dS - dpci_dS);
+ dPhaseCapPressure_dPhaseVolFrac += dF_dS * (pcd - pci);
+ }
+ else
+ {
+ GEOS_THROW( GEOS_FMT( "{}: State is {}.Shouldnt be used in pure DRAINAGE or IMBIBITION.",
+ "TableCapillaryPressureHysteresis",
+ (mode == ModeIndexType::DRAINAGE) ? "DRAINAGE" : ((mode ==
+ ModeIndexType::IMBIBITION)
+ ? "IMBIBITION"
+ : "UNKNOWN")),
+ InputError );
+ }
+
+
+ }
+}
+
+
+void TableCapillaryPressureHysteresis::KernelWrapper::computeBoundCapillaryPressure(
+ const TableFunction::KernelWrapper & drainageRelpermWrapper,
+ const geos::real64 & phaseVolFraction,
+ geos::real64 & phaseCapPressure,
+ geos::real64 & dPhaseCapPressure_dPhaseVolFrac ) const
+{
+ phaseCapPressure = drainageRelpermWrapper.compute( &phaseVolFraction,
+ &dPhaseCapPressure_dPhaseVolFrac );
+}
+
+/// Helper function to compute Pc(S) for given S, mode, and historical values
+/// Used for Newton-Raphson inversion in computeInv
+GEOS_HOST_DEVICE
+inline real64 TableCapillaryPressureHysteresis::KernelWrapper::computeCapillaryPressureForSaturation(
+ real64 const S,
+ fields::cappres::ModeIndexType const & mode,
+ integer const ipPhase,
+ real64 const & phaseMinHistoricalVolFraction,
+ real64 const & phaseMaxHistoricalVolFraction,
+ real64 const & phaseMode2PeakVolFraction,
+ arrayView1d< TableFunction::KernelWrapper const > const & capPresKernelWrappers,
+ KilloughHysteresis::HysteresisCurve const & wettingCurve,
+ KilloughHysteresis::HysteresisCurve const & nonWettingCurve,
+ real64 const & landParam,
+ real64 const & phaseIntermediateMinVolFraction,
+ real64 const & killoughCurvatureParam,
+ real64 const & jerauldParam_a,
+ real64 const & jerauldParam_b,
+ bool const isWettingPhase,
+ real64 const precomputedScrt,
+ real64 const precomputedDenomF,
+ real64 const precomputedShy ) const
+{
+ GEOS_UNUSED_VAR( ipPhase, landParam, jerauldParam_a, jerauldParam_b );
+ real64 pc = 0.0;
+ real64 dpc_dS = 0.0;
+
+ // For pure drainage or imbibition modes, use the table directly
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE || mode == fields::cappres::ModeIndexType::IMBIBITION )
+ {
+ integer const arrayIndex = (mode == fields::cappres::ModeIndexType::DRAINAGE) ? fields::cappres::ModeIndexType::DRAINAGE : fields::cappres::ModeIndexType::IMBIBITION;
+ if( arrayIndex < static_cast< integer >(capPresKernelWrappers.size()))
+ {
+ constexpr bool ENABLE_COMPUTE_PC_DEBUG = false;
+ if constexpr (ENABLE_COMPUTE_PC_DEBUG) {
+ std::cout << "[COMPUTE_PC_DEBUG] computeCapillaryPressureForSaturation: mode="
+ << (mode == fields::cappres::ModeIndexType::DRAINAGE ? "DRAINAGE" : "IMBIBITION")
+ << ", arrayIndex=" << arrayIndex
+ << ", S=" << S
+ << ", capPresKernelWrappers.size()=" << capPresKernelWrappers.size() << std::endl;
+ }
+ pc = capPresKernelWrappers[arrayIndex].compute( &S, &dpc_dS );
+ if constexpr (ENABLE_COMPUTE_PC_DEBUG) {
+ std::cout << "[COMPUTE_PC_DEBUG] After table.compute: pc=" << pc << ", dpc_dS=" << dpc_dS << std::endl;
+ }
+ }
+ }
+ // For scanning curves (DRAINAGE_TO_IMBIBITION or IMBIBITION_TO_DRAINAGE)
+ else
+ {
+ // Precomputed values should be provided by caller (from computeFlux before local_solver)
+ // If not provided, fall back to drainage curve to avoid calling computeTrappedCriticalPhaseVolFraction
+ if( precomputedScrt < 0.0 )
+ {
+ // Precomputed values not provided - return drainage curve value
+ real64 const arrayIndex = fields::cappres::ModeIndexType::DRAINAGE;
+ if( arrayIndex < static_cast< integer >(capPresKernelWrappers.size()))
+ {
+ pc = capPresKernelWrappers[arrayIndex].compute( &S, &dpc_dS );
+ }
+ return pc;
+ }
+
+ real64 dpci_dS, dpcd_dS;
+ real64 const pci = capPresKernelWrappers[fields::cappres::ModeIndexType::IMBIBITION].compute( &S, &dpci_dS );
+ real64 const pcd = capPresKernelWrappers[fields::cappres::ModeIndexType::DRAINAGE].compute( &S, &dpcd_dS );
+
+ real64 const E = killoughCurvatureParam;
+
+ if( isWettingPhase )
+ {
+ real64 const Smin = wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Smax = wettingCurve.drainageExtremaPhaseVolFraction;
+
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // DRAINAGE_TO_IMBIBITION: transitioning from drainage (low S) to imbibition (high S)
+ // Shy should be the minimum historical saturation (where drainage started)
+ real64 const Shy = (precomputedShy >= 0.0) ? precomputedShy :
+ ((phaseMinHistoricalVolFraction > Smin) ? phaseMinHistoricalVolFraction : Smin);
+
+ // Use precomputed value - should have been computed before local_solver
+ real64 const Scrt = precomputedScrt;
+ // For wetting curve, Scrt IS the max wetting saturation (Swma = Scrt)
+ // This matches the forward compute: Swma = 1 - (1 - Scrt) = Scrt
+ real64 const Swma = 1 - (1 - Scrt);
+ real64 denomF = precomputedDenomF;
+ if( LvArray::math::abs( precomputedDenomF ) < 1e-15 )
+ {
+ denomF = (1. / (Swma - Shy + E) - 1. / E);
+ }
+ // Guard against division by zero
+ real64 F = 0.0;
+ if( LvArray::math::abs( denomF ) >= 1e-15 )
+ {
+ real64 const F_num = (1. / (S - Shy + E) - 1. / E);
+ F = F_num / denomF;
+ }
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ pc = pcd + F * (pci - pcd);
+ dpc_dS = dpcd_dS + F * (dpci_dS - dpcd_dS);
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // IMBIBITION_TO_DRAINAGE: transitioning from imbibition (high S) to drainage (low S)
+ // Shy should be the maximum historical saturation (where imbibition started)
+ real64 const Shy = (precomputedShy >= 0.0) ? precomputedShy :
+ ((phaseMaxHistoricalVolFraction < Smax) ? phaseMaxHistoricalVolFraction : Smax);
+
+ // Use precomputed value - should have been computed before local_solver
+ real64 const Scrt = precomputedScrt;
+
+ real64 denomF = precomputedDenomF;
+ if( LvArray::math::abs( precomputedDenomF ) < 1e-15 )
+ {
+ denomF = (1. / (Shy - Scrt + E) - 1. / E);
+ }
+ // Guard against division by zero
+ real64 F = 0.0;
+ if( LvArray::math::abs( denomF ) >= 1e-15 )
+ {
+ real64 const F_num = (1. / (Shy - S + E) - 1. / E);
+ F = F_num / denomF;
+ }
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ pc = pci + F * (pcd - pci);
+ dpc_dS = dpci_dS + F * (dpcd_dS - dpci_dS);
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ // IMBIBITION_TO_DRAINAGE_FROM_SCANNING: Secondary drainage scanning curve (Mode 4)
+ // Based on Killough (1976) - solve quadratic for ghost departure point
+ real64 const H = (phaseMinHistoricalVolFraction > Smin) ? phaseMinHistoricalVolFraction : Smin;
+ real64 S_star = phaseMode2PeakVolFraction;
+ if( S_star < 1e-12 || S_star >= Smax - 1e-12 )
+ {
+ if( phaseMaxHistoricalVolFraction > H + 1e-12 && phaseMaxHistoricalVolFraction < Smax - 1e-12 )
+ {
+ S_star = phaseMaxHistoricalVolFraction;
+ }
+ else
+ {
+ S_star = LvArray::math::max( H + 0.1, LvArray::math::min( S, Smax - 0.01 ));
+ }
+ }
+
+ // Compute F_known from Mode 2 at S_star
+ real64 const Scrt = precomputedScrt;
+ // For wetting curve, Scrt IS the max wetting saturation (Swma = Scrt)
+ real64 const Swma = 1 - (1 - Scrt);
+ real64 F_known = 0.0;
+ if( S_star <= Swma + 1e-12 )
+ {
+ real64 const F_num = (1. / (S_star - H + E) - 1. / E);
+ real64 const F_denom = (1. / (Swma - H + E) - 1. / E);
+ if( LvArray::math::abs( F_denom ) > 1e-12 )
+ {
+ F_known = F_num / F_denom;
+ }
+ }
+ F_known = LvArray::math::max( 0.0, LvArray::math::min( 1.0, F_known ));
+
+ // F_star_target = 1 - F_known
+ real64 const F_star_target = 1.0 - F_known;
+
+ // Solve quadratic for x (ghost departure point)
+ real64 const a = S_star;
+ real64 const b = H; // Use H so curve rejoins drainage at H
+ real64 const T = F_star_target;
+ real64 const coeff_A = (1.0 - T);
+ real64 const coeff_B = -(1.0 - T) * (a + b - 2.0 * E) - (1.0 - T) * E;
+ real64 const coeff_C = (1.0 - T) * (a - E) * (b - E)
+ - E * E * (1.0 + T)
+ - E * (T * a - b);
+
+ real64 x = S_star;
+ real64 discriminant = coeff_B * coeff_B - 4.0 * coeff_A * coeff_C;
+ if( discriminant >= 0.0 && LvArray::math::abs( coeff_A ) > 1e-14 )
+ {
+ real64 sqrt_disc = LvArray::math::sqrt( discriminant );
+ real64 x1 = (-coeff_B + sqrt_disc) / (2.0 * coeff_A);
+ real64 x2 = (-coeff_B - sqrt_disc) / (2.0 * coeff_A);
+ if( x1 > S_star - 1e-8 && x2 > S_star - 1e-8 )
+ {
+ x = LvArray::math::min( x1, x2 );
+ }
+ else if( x1 > S_star - 1e-8 )
+ {
+ x = x1;
+ }
+ else if( x2 > S_star - 1e-8 )
+ {
+ x = x2;
+ }
+ }
+
+ // Compute F_star: F_star = [1/(x - S + E) - 1/E] / [1/(x - H + E) - 1/E]
+ real64 F_star = 1.0;
+ real64 const F_star_num = (1. / (x - S + E) - 1. / E);
+ real64 const F_star_denom = (1. / (x - H + E) - 1. / E);
+ if( LvArray::math::abs( F_star_denom ) > 1e-12 )
+ {
+ F_star = F_star_num / F_star_denom;
+ F_star = LvArray::math::max( 0.0, LvArray::math::min( 1.0, F_star ));
+ }
+
+ // Pc = Pc_Im + F_star * (Pc_Dr - Pc_Im)
+ pc = pci + F_star * (pcd - pci);
+ dpc_dS = dpci_dS + F_star * (dpcd_dS - dpci_dS);
+ }
+ }
+ else
+ {
+ // Non-wetting phase
+ real64 const Smax = nonWettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Shy = (precomputedShy >= 0.0) ? precomputedShy :
+ ((phaseMaxHistoricalVolFraction < Smax) ? phaseMaxHistoricalVolFraction : Smax);
+
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // Use precomputed value - should have been computed before local_solver
+ real64 const Scrt = precomputedScrt;
+
+ real64 denomF = precomputedDenomF;
+ if( LvArray::math::abs( precomputedDenomF ) < 1e-15 )
+ {
+ denomF = (1. / (Shy - Scrt + E) - 1. / E);
+ }
+ // Guard against division by zero
+ real64 F = 0.0;
+ if( LvArray::math::abs( denomF ) >= 1e-15 )
+ {
+ real64 const F_num = (1. / (Shy - S + E) - 1. / E);
+ F = F_num / denomF;
+ }
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ pc = pcd + F * (pci - pcd);
+ dpc_dS = dpci_dS + F * (dpci_dS - dpcd_dS);
+ // Note: there's also a dF/dS term in the non-wetting case, but for inversion we approximate
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // Use precomputed value - should have been computed before local_solver
+ real64 const Scrt = precomputedScrt;
+ real64 const Sgma = 1. - Scrt - phaseIntermediateMinVolFraction;
+
+ real64 denomF = precomputedDenomF;
+ if( LvArray::math::abs( precomputedDenomF ) < 1e-15 )
+ {
+ denomF = (1. / (Sgma - Shy + E) - 1. / E);
+ }
+ // Guard against division by zero
+ real64 F = 0.0;
+ if( LvArray::math::abs( denomF ) >= 1e-15 )
+ {
+ real64 const F_num = (1. / (S - Shy + E) - 1. / E);
+ F = F_num / denomF;
+ }
+ F = LvArray::math::max( F, 0.0 );
+ F = LvArray::math::min( F, 1.0 );
+
+ pc = pci + F * (pcd - pci);
+ dpc_dS = dpcd_dS + F * (dpcd_dS - dpci_dS);
+ // Note: there's also a dF/dS term in the non-wetting case, but for inversion we approximate
+ }
+ }
+ }
+
+ return pc;
+}
+
+void
+TableCapillaryPressureHysteresis::KernelWrapper::computeInv(
+ arraySlice1d< real64, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction,
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction,
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMode2PeakVolFraction,
+ arraySlice1d< real64 const, cappres::USD_CAPPRES - 2 > const & phaseTrappedVolFrac,
+ arraySlice1d< real64 const, cappres::USD_CAPPRES - 2 > const & phaseCapPressure,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPressure_dPhaseVolFrac,
+ fields::cappres::ModeIndexType const & mode ) const
+{
+ GEOS_UNUSED_VAR( phaseTrappedVolFrac );
+ LvArray::forValuesInSlice( dPhaseCapPressure_dPhaseVolFrac, []( real64 & val ) { val = 0.0; } );
+
+ constexpr bool ENABLE_COMPUTEINV_PATH_DEBUG = false;
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] Entry to computeInv(), mode="
+ << (mode == fields::cappres::ModeIndexType::DRAINAGE ? "DRAINAGE" :
+ mode == fields::cappres::ModeIndexType::IMBIBITION ? "IMBIBITION" : "SCANNING") << std::endl;
+ }
+
+ using PT = CapillaryPressureBase::PhaseType;
+ integer const ipWater = (PT::WATER < m_phaseOrder.size()) ? m_phaseOrder[PT::WATER] : -1;
+ integer const ipOil = (PT::OIL < m_phaseOrder.size()) ? m_phaseOrder[PT::OIL] : -1;
+ integer const ipGas = (PT::GAS < m_phaseOrder.size()) ? m_phaseOrder[PT::GAS] : -1;
+
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] Phase indices: ipWater=" << ipWater
+ << ", ipOil=" << ipOil << ", ipGas=" << ipGas << std::endl;
+ std::cout << "[COMPUTEINV_PATH] After phase indices calculation, continuing..." << std::endl;
+ }
+
+ constexpr real64 tol = 1e-9;
+ constexpr integer maxIter = 20;
+ constexpr real64 minS = 0.0;
+ constexpr real64 maxS = 1.0;
+
+ // Determine which phase pairs need inversion
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] Checking phase combination..." << std::endl;
+ std::cout << "[COMPUTEINV_PATH] ipWater=" << ipWater << ", ipOil=" << ipOil << ", ipGas=" << ipGas << std::endl;
+ bool isThreePhase = (ipWater >= 0 && ipOil >= 0 && ipGas >= 0);
+ std::cout << "[COMPUTEINV_PATH] Three-phase condition: " << (isThreePhase ? "TRUE" : "FALSE") << std::endl;
+ std::cout << "[COMPUTEINV_PATH] About to check three-phase if statement..." << std::endl;
+ }
+ if( ipWater >= 0 && ipOil >= 0 && ipGas >= 0 )
+ {
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] Taking THREE-PHASE path" << std::endl;
+ }
+ // Three-phase: invert wetting and non-wetting capillary pressures
+
+ // 1. Invert wetting phase (water-oil capillary pressure)
+ constexpr real64 pcEpsilon = 1e-10;
+ constexpr bool ENABLE_INVERSE_TABLE_DEBUG = false;
+ if( ipWater >= 0 && LvArray::math::abs( phaseCapPressure[ipWater] ) > pcEpsilon )
+ {
+ // For pure DRAINAGE or IMBIBITION modes, use direct table lookup (analytical inverse)
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE || mode == fields::cappres::ModeIndexType::IMBIBITION )
+ {
+ integer const arrayIndex = (mode == fields::cappres::ModeIndexType::DRAINAGE) ? 0 : 1;
+ array1d< real64 > input( 1 );
+ input[0] = phaseCapPressure[ipWater];
+ auto inputSlice = input.toSliceConst();
+
+ if constexpr (ENABLE_INVERSE_TABLE_DEBUG) {
+ real64 S_before = phaseVolFraction[ipWater];
+ real64 dS_dPc_before = dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater];
+ std::cout << "[INVERSE_TABLE_DEBUG] Cell1 (water), mode=" << (mode == fields::cappres::ModeIndexType::DRAINAGE ? "DRAINAGE" : "IMBIBITION")
+ << ", arrayIndex=" << arrayIndex << std::endl;
+ std::cout << " Input Pc=" << input[0] << std::endl;
+ std::cout << " S before inverse table=" << S_before << std::endl;
+ std::cout << " dS_dPc before inverse table=" << dS_dPc_before << std::endl;
+ }
+
+ // Match TableCapillaryPressure exactly: pass derivative pointer directly to inverse table
+ // Note: The inverse table returns dS/dPc, but we store it directly like TableCapillaryPressure does
+ // The local solver will call compute() afterwards to get the correct dPc/dS derivative
+ phaseVolFraction[ipWater] = m_inverseWettingIntermediateCapillaryPressureKernelWrappers[arrayIndex].compute(
+ inputSlice, &dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater] );
+
+ if constexpr (ENABLE_INVERSE_TABLE_DEBUG) {
+ real64 S_after = phaseVolFraction[ipWater];
+ real64 dS_dPc_after = dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater];
+ std::cout << " S after inverse table=" << S_after << std::endl;
+ std::cout << " dS_dPc after inverse table=" << dS_dPc_after << std::endl;
+ }
+
+ phaseVolFraction[ipOil] = 1.0 - phaseVolFraction[ipWater] - phaseVolFraction[ipGas];
+ // Direct lookup complete, skip Newton-Raphson
+ }
+ else
+ {
+ // For scanning curves, use analytical inverse if possible, otherwise Newton-Raphson
+ // TEMPORARY: Flag to enable analytical inverse for scanning curves
+ constexpr bool USE_ANALYTICAL_INVERSE_SCANNING = true;
+
+ real64 S_guess = phaseMaxHistoricalVolFraction[ipWater];
+ if( S_guess <= phaseMinHistoricalVolFraction[ipWater] || S_guess< minS || S_guess > maxS )
+ {
+ // Fall back to drainage/imbibition curve evaluation if available
+ real64 const Smin = m_wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Smax = m_wettingCurve.drainageExtremaPhaseVolFraction;
+ S_guess = 0.5 * (Smin + Smax);
+ S_guess = LvArray::math::max( S_guess, minS );
+ S_guess = LvArray::math::min( S_guess, maxS );
+ }
+
+ // Precompute fixed parameters for scanning curves (these don't change during Newton-Raphson)
+ real64 precomputedScrt_water = -1.0;
+ real64 precomputedDenomF_water = 0.0;
+ real64 precomputedShy_water = -1.0;
+
+ // Precompute for scanning curves (Mode 2, Mode 3, or Mode 4)
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE ||
+ mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ real64 const Smin = m_wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Smax = m_wettingCurve.drainageExtremaPhaseVolFraction;
+ real64 const E = m_killoughCurvatureParamCapPres;
+
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // DRAINAGE_TO_IMBIBITION: Shy should be minimum historical (where drainage started)
+ precomputedShy_water = (phaseMinHistoricalVolFraction[ipWater] > Smin) ?
+ phaseMinHistoricalVolFraction[ipWater] : Smin;
+
+ // Compute Scrt for DRAINAGE_TO_IMBIBITION scanning curve (wetting phase)
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, precomputedShy_water,
+ m_landParam[ipWater],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ precomputedScrt_water = Scrt;
+ // For wetting curve, Scrt IS the max wetting saturation (Swma = Scrt)
+ real64 const Swma = 1. - (1. - Scrt);
+ // Compute denomF for DRAINAGE_TO_IMBIBITION: denomF = (1. / (Swma - Shy + E) - 1. / E)
+ precomputedDenomF_water = (1. / (Swma - precomputedShy_water + E) - 1. / E);
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // IMBIBITION_TO_DRAINAGE: Shy should be maximum historical (where imbibition started)
+ precomputedShy_water = (phaseMaxHistoricalVolFraction[ipWater] < Smax) ?
+ phaseMaxHistoricalVolFraction[ipWater] : Smax;
+
+ // Compute Scrt for IMBIBITION_TO_DRAINAGE scanning curve (wetting phase)
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, precomputedShy_water,
+ m_landParam[ipWater],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ precomputedScrt_water = Scrt;
+ // Compute denomF for IMBIBITION_TO_DRAINAGE: denomF = (1. / (Shy - Scrt + E) - 1. / E)
+ precomputedDenomF_water = (1. / (precomputedShy_water - Scrt + E) - 1. / E);
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ // Mode 4: IMBIBITION_TO_DRAINAGE_FROM_SCANNING
+ // H (first reversal point) should be minimum historical (where imbibition started)
+ // This is used to compute Scrt for Mode 4
+ real64 const H = (phaseMinHistoricalVolFraction[ipWater] > Smin) ?
+ phaseMinHistoricalVolFraction[ipWater] : Smin;
+
+ // Compute Scrt for Mode 4 based on H (first reversal point)
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, H,
+ m_landParam[ipWater],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ precomputedScrt_water = Scrt;
+ // For Mode 4, precomputedShy is not used in the same way, but set it to H for consistency
+ precomputedShy_water = H;
+ // denomF is not used for Mode 4 (it solves quadratic instead), but set to 0 to indicate it's not applicable
+ precomputedDenomF_water = 0.0;
+ }
+ }
+
+ real64 S = S_guess;
+
+ // Try analytical inverse for scanning curves if enabled
+ if( USE_ANALYTICAL_INVERSE_SCANNING )
+ {
+ // Use inverse tables to get bounds: S_dr(Pc) and S_im(Pc)
+ array1d< real64 > input_dr( 1 ), input_im( 1 );
+ input_dr[0] = phaseCapPressure[ipWater];
+ input_im[0] = phaseCapPressure[ipWater];
+ auto inputSlice_dr = input_dr.toSliceConst();
+ auto inputSlice_im = input_im.toSliceConst();
+
+ real64 dS_dPc_dr = 0.0, dS_dPc_im = 0.0;
+ real64 S_dr = m_inverseWettingIntermediateCapillaryPressureKernelWrappers[ModeIndexType::DRAINAGE].compute(
+ inputSlice_dr, &dS_dPc_dr );
+ real64 S_im = m_inverseWettingIntermediateCapillaryPressureKernelWrappers[ModeIndexType::IMBIBITION].compute(
+ inputSlice_im, &dS_dPc_im );
+
+ // Clamp to valid range
+ S_dr = LvArray::math::max( minS, LvArray::math::min( maxS, S_dr ));
+ S_im = LvArray::math::max( minS, LvArray::math::min( maxS, S_im ));
+
+ // For scanning curves, S is between S_dr and S_im (order depends on mode)
+ real64 S_low = LvArray::math::min( S_dr, S_im );
+ real64 S_high = LvArray::math::max( S_dr, S_im );
+
+ // Use analytical inverse based on F(S) formula
+ real64 const E = m_killoughCurvatureParamCapPres;
+ real64 const Pc_target = phaseCapPressure[ipWater];
+
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // DRAINAGE_TO_IMBIBITION: Pc = Pc_dr(S) + F(S) * [Pc_im(S) - Pc_dr(S)]
+ // F(S) = (1. / (S - Shy + E) - 1. / E) / denomF
+ // Rearranging: S = Shy - E + 1 / (F(S) * denomF + 1/E)
+ real64 const Shy = precomputedShy_water;
+ real64 const denomF = precomputedDenomF_water;
+
+ // Initial guess: interpolate between S_dr and S_im
+ S = 0.5 * (S_low + S_high);
+
+ // Fixed-point iteration using analytical F(S) formula
+ for( integer iter = 0; iter < 10; ++iter )
+ {
+ // Compute F(S) from current S
+ real64 F_S = (1. / (S - Shy + E) - 1. / E) / denomF;
+ F_S = LvArray::math::max( 0.0, LvArray::math::min( 1.0, F_S ));
+
+ // Compute Pc(S) to check convergence
+ real64 pc_computed = this->computeCapillaryPressureForSaturation(
+ S, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ true, // isWettingPhase
+ precomputedScrt_water,
+ precomputedDenomF_water,
+ precomputedShy_water );
+
+ if( LvArray::math::abs( pc_computed - Pc_target ) < tol )
+ {
+ break;
+ }
+
+ real64 denom_F = F_S * denomF + 1. / E;
+ if( LvArray::math::abs( denom_F ) > 1e-12 )
+ {
+ real64 S_new = Shy - E + 1. / denom_F;
+ S_new = LvArray::math::max( S_low, LvArray::math::min( S_high, S_new ));
+ S = S_new;
+ }
+ else
+ {
+ // Fall back to interpolation if denominator is too small
+ S = 0.5 * (S + 0.5 * (S_low + S_high));
+ }
+ }
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // IMBIBITION_TO_DRAINAGE: Pc = Pc_im(S) + F(S) * [Pc_dr(S) - Pc_im(S)]
+ // F(S) = (1. / (S - Shy + E) - 1. / E) / denomF
+ real64 const Shy = precomputedShy_water;
+ real64 const denomF = precomputedDenomF_water;
+
+ S = 0.5 * (S_low + S_high);
+
+ for( integer iter = 0; iter < 10; ++iter )
+ {
+ real64 F_S = (1. / (S - Shy + E) - 1. / E) / denomF;
+ F_S = LvArray::math::max( 0.0, LvArray::math::min( 1.0, F_S ));
+
+ real64 pc_computed = this->computeCapillaryPressureForSaturation(
+ S, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ true, // isWettingPhase
+ precomputedScrt_water,
+ precomputedDenomF_water,
+ precomputedShy_water );
+
+ if( LvArray::math::abs( pc_computed - Pc_target ) < tol )
+ {
+ break;
+ }
+
+ real64 denom_F = F_S * denomF + 1. / E;
+ if( LvArray::math::abs( denom_F ) > 1e-12 )
+ {
+ real64 S_new = Shy - E + 1. / denom_F;
+ S_new = LvArray::math::max( S_low, LvArray::math::min( S_high, S_new ));
+ S = S_new;
+ }
+ else
+ {
+ S = 0.5 * (S + 0.5 * (S_low + S_high));
+ }
+ }
+ }
+ // For IMBIBITION_TO_DRAINAGE_FROM_SCANNING, fall through to Newton-Raphson (more complex F_star formula)
+ }
+
+ real64 pc_check = this->computeCapillaryPressureForSaturation(
+ S, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ true, // isWettingPhase
+ precomputedScrt_water,
+ precomputedDenomF_water,
+ precomputedShy_water );
+
+ bool needs_newton = (mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING) ||
+ (LvArray::math::abs( pc_check - phaseCapPressure[ipWater] ) >= tol);
+
+ if( needs_newton )
+ {
+ real64 residual_prev = 1e30;
+
+ for( integer iter = 0; iter < maxIter; ++iter )
+ {
+ // Compute Pc(S) using the helper function
+ real64 pc_computed = this->computeCapillaryPressureForSaturation(
+ S, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ true, // isWettingPhase
+ precomputedScrt_water,
+ precomputedDenomF_water,
+ precomputedShy_water );
+
+ real64 residual = pc_computed - phaseCapPressure[ipWater];
+
+ if( LvArray::math::abs( residual ) < tol )
+ {
+ break;
+ }
+
+ // Compute derivative dPc/dS using adaptive finite difference
+ // Use relative step size to handle different scales
+ real64 const dS = LvArray::math::max( 1e-8, 1e-6 * LvArray::math::max( LvArray::math::abs( S ), 1e-6 ));
+ real64 S_pert = S + dS;
+ if( S_pert > maxS )
+ {
+ S_pert = LvArray::math::max( S - dS, minS );
+ }
+
+ real64 const pc_pert = this->computeCapillaryPressureForSaturation(
+ S_pert, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ true, // isWettingPhase
+ precomputedScrt_water,
+ precomputedDenomF_water,
+ precomputedShy_water );
+
+ real64 const dpc_dS = (pc_pert - pc_computed) / (S_pert - S);
+
+ if( LvArray::math::abs( dpc_dS ) > 1e-12 )
+ {
+ real64 const newtonStep = -residual / dpc_dS;
+ real64 const maxStep = 0.1; // Limit step size to prevent overshooting
+ real64 const step = LvArray::math::max( -maxStep, LvArray::math::min( maxStep, newtonStep ));
+
+ real64 S_new = S + step;
+
+ // Line search: if residual increases, reduce step
+ if( iter > 0 && LvArray::math::abs( residual ) > LvArray::math::abs( residual_prev ))
+ {
+ // Backtrack: use smaller step
+ S_new = S + 0.5 * step;
+ }
+
+ // Clamp to valid range
+ S_new = LvArray::math::max( S_new, minS );
+ S_new = LvArray::math::min( S_new, maxS );
+
+ if( LvArray::math::abs( S_new - S ) < 1e-10 &&
+ (S_new <= minS + 1e-10 || S_new >= maxS - 1e-10))
+ {
+ // Use bisection between current guess and boundary
+ S_new = 0.5 * (S + (S_new <= minS + 1e-10 ? minS : maxS));
+ }
+
+ residual_prev = residual;
+ S = S_new;
+ }
+ else
+ {
+ // If derivative is zero or very small, use bisection
+ real64 const S_low = LvArray::math::max( S - 0.1, minS );
+ real64 const S_high = LvArray::math::min( S + 0.1, maxS );
+ S = 0.5 * (S_low + S_high);
+ S = LvArray::math::max( S, minS );
+ S = LvArray::math::min( S, maxS );
+ }
+ }
+
+ phaseVolFraction[ipWater] = S;
+ phaseVolFraction[ipOil] = 1.0 - S - phaseVolFraction[ipGas];
+
+ // Compute derivative at final S
+ real64 dpc_dS_final = 0.0;
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE || mode == fields::cappres::ModeIndexType::IMBIBITION )
+ {
+ integer const arrayIndex = (mode == fields::cappres::ModeIndexType::DRAINAGE) ? fields::cappres::ModeIndexType::DRAINAGE : fields::cappres::ModeIndexType::IMBIBITION;
+ m_wettingIntermediateCapillaryPressureKernelWrappers[arrayIndex].compute( &S, &dpc_dS_final );
+ }
+ else
+ {
+ // For scanning curves, compute derivative using finite difference
+ real64 const dS_final = 1e-6;
+ real64 const S_pert_final = LvArray::math::min( S + dS_final, maxS );
+ real64 const pc_final = this->computeCapillaryPressureForSaturation(
+ S, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ true, // isWettingPhase
+ precomputedScrt_water,
+ precomputedDenomF_water,
+ precomputedShy_water );
+ real64 const pc_pert_final = this->computeCapillaryPressureForSaturation(
+ S_pert_final, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ true, // isWettingPhase
+ precomputedScrt_water,
+ precomputedDenomF_water,
+ precomputedShy_water );
+ dpc_dS_final = (pc_pert_final - pc_final) / dS_final;
+ }
+ dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater] = dpc_dS_final;
+ } // End else block for scanning curves
+ }
+ } // Close if (ipWater >= 0) block
+
+ // 2. Invert non-wetting phase (gas-oil capillary pressure)
+ if( ipGas >= 0 && LvArray::math::abs( phaseCapPressure[ipGas] ) > pcEpsilon )
+ {
+ // For pure DRAINAGE or IMBIBITION modes, use direct table lookup (analytical inverse)
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE || mode == fields::cappres::ModeIndexType::IMBIBITION )
+ {
+ integer const arrayIndex = (mode == fields::cappres::ModeIndexType::DRAINAGE) ? 0 : 1;
+ array1d< real64 > input( 1 );
+ input[0] = phaseCapPressure[ipGas];
+ auto inputSlice = input.toSliceConst();
+
+ if constexpr (ENABLE_INVERSE_TABLE_DEBUG) {
+ real64 S_before = phaseVolFraction[ipGas];
+ real64 dS_dPc_before = dPhaseCapPressure_dPhaseVolFrac[ipGas][ipGas];
+ std::cout << "[INVERSE_TABLE_DEBUG] Cell2 (gas), mode=" << (mode == fields::cappres::ModeIndexType::DRAINAGE ? "DRAINAGE" : "IMBIBITION")
+ << ", arrayIndex=" << arrayIndex << std::endl;
+ std::cout << " Input Pc=" << input[0] << std::endl;
+ std::cout << " S before inverse table=" << S_before << std::endl;
+ std::cout << " dS_dPc before inverse table=" << dS_dPc_before << std::endl;
+ }
+
+ // Match TableCapillaryPressure exactly: pass derivative pointer directly to inverse table
+ // Note: The inverse table returns dS/dPc, but we store it directly like TableCapillaryPressure does
+ // The local solver will call compute() afterwards to get the correct dPc/dS derivative
+ phaseVolFraction[ipGas] = m_inverseNonWettingIntermediateCapillaryPressureKernelWrappers[arrayIndex].compute(
+ inputSlice, &dPhaseCapPressure_dPhaseVolFrac[ipGas][ipGas] );
+
+ if constexpr (ENABLE_INVERSE_TABLE_DEBUG) {
+ real64 S_after = phaseVolFraction[ipGas];
+ real64 dS_dPc_after = dPhaseCapPressure_dPhaseVolFrac[ipGas][ipGas];
+ std::cout << " S after inverse table=" << S_after << std::endl;
+ std::cout << " dS_dPc after inverse table=" << dS_dPc_after << std::endl;
+ }
+
+ if( ipWater >= 0 && ipOil >= 0 )
+ {
+ phaseVolFraction[ipOil] = 1.0 - phaseVolFraction[ipWater] - phaseVolFraction[ipGas];
+ }
+ // Direct lookup complete, skip Newton-Raphson
+ }
+ else
+ {
+ // For scanning curves, use Newton-Raphson
+ // Note: For non-wetting phase, the capillary pressure is typically negative
+ // and the relationship may be inverted (increasing Pc with decreasing S)
+ real64 S_guess = phaseMaxHistoricalVolFraction[ipGas];
+ if( S_guess <= phaseMinHistoricalVolFraction[ipGas] || S_guess< minS || S_guess > maxS )
+ {
+ real64 const Smin = m_nonWettingCurve.imbibitionExtremaPhaseVolFraction;
+ real64 const Smax = m_nonWettingCurve.drainageExtremaPhaseVolFraction;
+ S_guess = 0.5 * (Smin + Smax);
+ S_guess = LvArray::math::max( S_guess, minS );
+ S_guess = LvArray::math::min( S_guess, maxS );
+ }
+
+ // Precompute fixed parameters for scanning curves (these don't change during Newton-Raphson)
+ real64 precomputedScrt_gas = -1.0;
+ real64 precomputedDenomF_gas = 0.0;
+ real64 precomputedShy_gas = -1.0;
+
+ // Only precompute for scanning curves (DRAINAGE_TO_IMBIBITION or IMBIBITION_TO_DRAINAGE)
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ real64 const Smax = m_nonWettingCurve.oppositeBoundPhaseVolFraction;
+ precomputedShy_gas = (phaseMaxHistoricalVolFraction[ipGas] < Smax) ?
+ phaseMaxHistoricalVolFraction[ipGas] : Smax;
+ real64 const E = m_killoughCurvatureParamCapPres;
+
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // Compute Scrt for DRAINAGE_TO_IMBIBITION scanning curve
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve, precomputedShy_gas,
+ m_landParam[ipGas],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ precomputedScrt_gas = Scrt;
+ // Compute denomF for DRAINAGE_TO_IMBIBITION: denomF = (1. / (Shy - Scrt + E) - 1. / E)
+ precomputedDenomF_gas = (1. / (precomputedShy_gas - Scrt + E) - 1. / E);
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // Compute Scrt for IMBIBITION_TO_DRAINAGE scanning curve
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, precomputedShy_gas,
+ m_landParam[ipGas],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ precomputedScrt_gas = Scrt;
+ real64 const Sgma = 1. - Scrt - m_phaseIntermediateMinVolFraction;
+ // Compute denomF for IMBIBITION_TO_DRAINAGE: denomF = (1. / (Sgma - Shy + E) - 1. / E)
+ precomputedDenomF_gas = (1. / (Sgma - precomputedShy_gas + E) - 1. / E);
+ }
+ }
+
+ real64 S = S_guess;
+ real64 residual_prev = 1e30;
+
+ for( integer iter = 0; iter < maxIter; ++iter )
+ {
+ real64 pc_computed = this->computeCapillaryPressureForSaturation(
+ S, mode, ipGas,
+ phaseMinHistoricalVolFraction[ipGas],
+ phaseMaxHistoricalVolFraction[ipGas],
+ phaseMode2PeakVolFraction[ipGas],
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipGas],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ false, // isWettingPhase = false
+ precomputedScrt_gas,
+ precomputedDenomF_gas,
+ precomputedShy_gas );
+
+ // For non-wetting phase, capillary pressure is typically multiplied by -1
+ // Check which sign to use based on the input
+ real64 residual = pc_computed - phaseCapPressure[ipGas];
+
+ if( LvArray::math::abs( residual ) < tol )
+ {
+ break;
+ }
+
+ // Compute derivative dPc/dS using adaptive finite difference
+ real64 const dS = LvArray::math::max( 1e-8, 1e-6 * LvArray::math::max( LvArray::math::abs( S ), 1e-6 ));
+ real64 S_pert = S + dS;
+ if( S_pert > maxS )
+ {
+ S_pert = LvArray::math::max( S - dS, minS );
+ }
+
+ real64 const pc_pert = this->computeCapillaryPressureForSaturation(
+ S_pert, mode, ipGas,
+ phaseMinHistoricalVolFraction[ipGas],
+ phaseMaxHistoricalVolFraction[ipGas],
+ phaseMode2PeakVolFraction[ipGas],
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipGas],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ false, // isWettingPhase = false
+ precomputedScrt_gas,
+ precomputedDenomF_gas,
+ precomputedShy_gas );
+
+ real64 const dpc_dS = (pc_pert - pc_computed) / (S_pert - S);
+
+ if( LvArray::math::abs( dpc_dS ) > 1e-12 )
+ {
+ real64 const newtonStep = -residual / dpc_dS;
+ real64 const maxStep = 0.1; // Limit step size to prevent overshooting
+ real64 const step = LvArray::math::max( -maxStep, LvArray::math::min( maxStep, newtonStep ));
+
+ real64 S_new = S + step;
+
+ // Line search: if residual increases, reduce step
+ if( iter > 0 && LvArray::math::abs( residual ) > LvArray::math::abs( residual_prev ))
+ {
+ // Backtrack: use smaller step
+ S_new = S + 0.5 * step;
+ }
+
+ // Clamp to valid range
+ S_new = LvArray::math::max( S_new, minS );
+ S_new = LvArray::math::min( S_new, maxS );
+
+ if( LvArray::math::abs( S_new - S ) < 1e-10 &&
+ (S_new <= minS + 1e-10 || S_new >= maxS - 1e-10))
+ {
+ // Use bisection between current guess and boundary
+ S_new = 0.5 * (S + (S_new <= minS + 1e-10 ? minS : maxS));
+ }
+
+ residual_prev = residual;
+ S = S_new;
+ }
+ else
+ {
+ // If derivative is zero or very small, use bisection
+ real64 const S_low = LvArray::math::max( S - 0.1, minS );
+ real64 const S_high = LvArray::math::min( S + 0.1, maxS );
+ S = 0.5 * (S_low + S_high);
+ S = LvArray::math::max( S, minS );
+ S = LvArray::math::min( S, maxS );
+ }
+ }
+
+ phaseVolFraction[ipGas] = S;
+
+ if( ipWater >= 0 && ipOil >= 0 )
+ {
+ phaseVolFraction[ipOil] = 1.0 - phaseVolFraction[ipWater] - phaseVolFraction[ipGas];
+ phaseVolFraction[ipOil] = LvArray::math::max( phaseVolFraction[ipOil], 0.0 );
+ phaseVolFraction[ipOil] = LvArray::math::min( phaseVolFraction[ipOil], 1.0 );
+ }
+
+ // Compute derivative at final S
+ real64 dpc_dS_final = 0.0;
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE || mode == fields::cappres::ModeIndexType::IMBIBITION )
+ {
+ integer const arrayIndex = (mode == fields::cappres::ModeIndexType::DRAINAGE) ? fields::cappres::ModeIndexType::DRAINAGE : fields::cappres::ModeIndexType::IMBIBITION;
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers[arrayIndex].compute( &S, &dpc_dS_final );
+ }
+ else
+ {
+ // For scanning curves, compute derivative using finite difference
+ real64 const dS_final = 1e-6;
+ real64 const S_pert_final = LvArray::math::min( S + dS_final, maxS );
+ real64 const pc_final = this->computeCapillaryPressureForSaturation(
+ S, mode, ipGas,
+ phaseMinHistoricalVolFraction[ipGas],
+ phaseMaxHistoricalVolFraction[ipGas],
+ phaseMode2PeakVolFraction[ipGas],
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipGas],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ false, // isWettingPhase = false
+ precomputedScrt_gas,
+ precomputedDenomF_gas,
+ precomputedShy_gas );
+ real64 const pc_pert_final = this->computeCapillaryPressureForSaturation(
+ S_pert_final, mode, ipGas,
+ phaseMinHistoricalVolFraction[ipGas],
+ phaseMaxHistoricalVolFraction[ipGas],
+ phaseMode2PeakVolFraction[ipGas],
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipGas],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ false, // isWettingPhase = false
+ precomputedScrt_gas,
+ precomputedDenomF_gas,
+ precomputedShy_gas );
+ dpc_dS_final = (pc_pert_final - pc_final) / dS_final;
+ }
+ dPhaseCapPressure_dPhaseVolFrac[ipGas][ipGas] = dpc_dS_final;
+ } // End else block for scanning curves
+ }
+ }
+ // CRITICAL: Add debug right after three-phase block to see if we reach here
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] *** AFTER three-phase block, before else-if checks ***" << std::endl;
+ std::cout << "[COMPUTEINV_PATH] ipWater=" << ipWater << ", ipOil=" << ipOil << ", ipGas=" << ipGas << std::endl;
+ std::cout << "[COMPUTEINV_PATH] Three-phase block was SKIPPED (condition was false)" << std::endl;
+ std::cout << "[COMPUTEINV_PATH] About to check if (ipWater < 0)..." << std::endl;
+ }
+ if( ipWater < 0 )
+ {
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] *** TAKING ipWater < 0 path (oil-gas) ***" << std::endl;
+ std::cout << "[COMPUTEINV_PATH] This should NOT happen with ipWater=0!" << std::endl;
+ }
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] After three-phase block, checking else-if conditions..." << std::endl;
+ std::cout << "[COMPUTEINV_PATH] ipWater=" << ipWater << ", condition (ipWater < 0)=" << (ipWater < 0 ? "TRUE" : "FALSE") << std::endl;
+ std::cout << "[COMPUTEINV_PATH] *** TAKING ipWater < 0 path (oil-gas) ***" << std::endl;
+ std::cout << "[COMPUTEINV_PATH] This should NOT happen with ipWater=0!" << std::endl;
+ }
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] *** TAKING ipWater < 0 path (oil-gas) ***" << std::endl;
+ std::cout << "[COMPUTEINV_PATH] This should NOT happen with ipWater=0!" << std::endl;
+ }
+ // Two-phase: oil-gas (non-wetting phase)
+ // Similar to above but simpler
+ constexpr real64 pcEpsilon_gas = 1e-10;
+ if( ipGas >= 0 && LvArray::math::abs( phaseCapPressure[ipGas] ) > pcEpsilon_gas )
+ {
+ // For pure DRAINAGE or IMBIBITION modes, use direct table lookup (analytical inverse)
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE || mode == fields::cappres::ModeIndexType::IMBIBITION )
+ {
+ integer const arrayIndex = (mode == fields::cappres::ModeIndexType::DRAINAGE) ? 0 : 1;
+ array1d< real64 > input( 1 );
+ input[0] = phaseCapPressure[ipGas];
+ auto inputSlice = input.toSliceConst();
+ // Match TableCapillaryPressure: no clamping, let the table handle bounds
+ phaseVolFraction[ipGas] = m_inverseNonWettingIntermediateCapillaryPressureKernelWrappers[arrayIndex].compute(
+ inputSlice, &dPhaseCapPressure_dPhaseVolFrac[ipGas][ipGas] );
+ if( ipOil >= 0 )
+ {
+ phaseVolFraction[ipOil] = 1.0 - phaseVolFraction[ipGas];
+ }
+ // Direct lookup complete, skip Newton-Raphson
+ }
+ else
+ {
+ // For scanning curves, use Newton-Raphson
+ real64 S_guess = phaseMaxHistoricalVolFraction[ipGas];
+ if( S_guess < minS || S_guess > maxS )
+ {
+ S_guess = 0.5;
+ }
+
+ // Precompute fixed parameters for scanning curves (these don't change during Newton-Raphson)
+ real64 precomputedScrt_gas = -1.0;
+ real64 precomputedDenomF_gas = 0.0;
+ real64 precomputedShy_gas = -1.0;
+
+ // Only precompute for scanning curves (DRAINAGE_TO_IMBIBITION or IMBIBITION_TO_DRAINAGE)
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ real64 const Smax = m_nonWettingCurve.oppositeBoundPhaseVolFraction;
+ precomputedShy_gas = (phaseMaxHistoricalVolFraction[ipGas] < Smax) ?
+ phaseMaxHistoricalVolFraction[ipGas] : Smax;
+ real64 const E = m_killoughCurvatureParamCapPres;
+
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // Compute Scrt for DRAINAGE_TO_IMBIBITION scanning curve
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve, precomputedShy_gas,
+ m_landParam[ipGas],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ precomputedScrt_gas = Scrt;
+ // Compute denomF for DRAINAGE_TO_IMBIBITION: denomF = (1. / (Shy - Scrt + E) - 1. / E)
+ precomputedDenomF_gas = (1. / (precomputedShy_gas - Scrt + E) - 1. / E);
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // Compute Scrt for IMBIBITION_TO_DRAINAGE scanning curve
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, precomputedShy_gas,
+ m_landParam[ipGas],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ precomputedScrt_gas = Scrt;
+ real64 const Sgma = 1. - Scrt - m_phaseIntermediateMinVolFraction;
+ // Compute denomF for IMBIBITION_TO_DRAINAGE: denomF = (1. / (Sgma - Shy + E) - 1. / E)
+ precomputedDenomF_gas = (1. / (Sgma - precomputedShy_gas + E) - 1. / E);
+ }
+ }
+
+ real64 S = S_guess;
+ for( integer iter = 0; iter < maxIter; ++iter )
+ {
+ real64 pc_computed = this->computeCapillaryPressureForSaturation(
+ S, mode, ipGas,
+ phaseMinHistoricalVolFraction[ipGas],
+ phaseMaxHistoricalVolFraction[ipGas],
+ phaseMode2PeakVolFraction[ipGas],
+ m_wettingNonWettingCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipGas],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ false, // isWettingPhase = false
+ precomputedScrt_gas,
+ precomputedDenomF_gas,
+ precomputedShy_gas );
+
+ real64 residual = pc_computed - phaseCapPressure[ipGas];
+
+ if( LvArray::math::abs( residual ) < tol )
+ {
+ break;
+ }
+
+ real64 const dS = 1e-6;
+ real64 const S_pert = LvArray::math::min( S + dS, maxS );
+ real64 const pc_pert = this->computeCapillaryPressureForSaturation(
+ S_pert, mode, ipGas,
+ phaseMinHistoricalVolFraction[ipGas],
+ phaseMaxHistoricalVolFraction[ipGas],
+ phaseMode2PeakVolFraction[ipGas],
+ m_wettingNonWettingCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipGas],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ false, // isWettingPhase = false
+ precomputedScrt_gas,
+ precomputedDenomF_gas,
+ precomputedShy_gas );
+
+ real64 const dpc_dS = (pc_pert - pc_computed) / dS;
+
+ if( LvArray::math::abs( dpc_dS ) > 1e-12 )
+ {
+ S = S - residual / dpc_dS;
+ S = LvArray::math::max( S, minS );
+ S = LvArray::math::min( S, maxS );
+ }
+ else
+ {
+ S = S - residual * 1e-6;
+ S = LvArray::math::max( S, minS );
+ S = LvArray::math::min( S, maxS );
+ }
+ }
+
+ phaseVolFraction[ipGas] = S;
+ if( ipOil >= 0 )
+ {
+ phaseVolFraction[ipOil] = 1.0 - S;
+ }
+ } // End else block for scanning curves
+ }
+ }
+ else
+ {
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] *** REACHED TWO-PHASE path (else block) ***" << std::endl;
+ std::cout << "[COMPUTEINV_PATH] ipWater=" << ipWater << ", ipOil=" << ipOil << ", ipGas=" << ipGas << std::endl;
+ std::cout << "[COMPUTEINV_PATH] About to check if (ipWater >= 0)" << std::endl;
+ std::cout << "[COMPUTEINV_PATH] This is the path that should work for Mode 0 (DRAINAGE)!" << std::endl;
+ }
+ // Two-phase: water-oil or water-gas (wetting phase)
+ // Copy exact pattern from TableCapillaryPressure::computeInv
+ if( ipWater >= 0 )
+ {
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] Two-phase: ipWater >= 0, entering water phase block" << std::endl;
+ std::cout << "[COMPUTEINV_PATH] About to check mode: mode=" << static_cast< int >(mode)
+ << ", DRAINAGE=" << static_cast< int >(fields::cappres::ModeIndexType::DRAINAGE)
+ << ", IMBIBITION=" << static_cast< int >(fields::cappres::ModeIndexType::IMBIBITION) << std::endl;
+ }
+ // For pure DRAINAGE or IMBIBITION modes, use direct table lookup (analytical inverse)
+ // CRITICAL DEBUG: Check if mode condition is actually true
+ bool isDrainage = (mode == fields::cappres::ModeIndexType::DRAINAGE);
+ bool isImbibition = (mode == fields::cappres::ModeIndexType::IMBIBITION);
+ bool isPureMode = (isDrainage || isImbibition);
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] Mode condition check:" << std::endl;
+ std::cout << "[COMPUTEINV_PATH] mode (as int)=" << static_cast< int >(mode) << std::endl;
+ std::cout << "[COMPUTEINV_PATH] DRAINAGE (as int)=" << static_cast< int >(fields::cappres::ModeIndexType::DRAINAGE) << std::endl;
+ std::cout << "[COMPUTEINV_PATH] IMBIBITION (as int)=" << static_cast< int >(fields::cappres::ModeIndexType::IMBIBITION) << std::endl;
+ std::cout << "[COMPUTEINV_PATH] isDrainage=" << (isDrainage ? "TRUE" : "FALSE") << std::endl;
+ std::cout << "[COMPUTEINV_PATH] isImbibition=" << (isImbibition ? "TRUE" : "FALSE") << std::endl;
+ std::cout << "[COMPUTEINV_PATH] isPureMode (DRAINAGE || IMBIBITION)=" << (isPureMode ? "TRUE" : "FALSE") << std::endl;
+ }
+ if( isPureMode )
+ {
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] Using pure DRAINAGE/IMBIBITION path (same as working case)" << std::endl;
+ std::cout << "[COMPUTEINV_PATH] mode=" << (mode == fields::cappres::ModeIndexType::DRAINAGE ? "DRAINAGE" : "IMBIBITION") << std::endl;
+ }
+ integer const arrayIndex = (mode == fields::cappres::ModeIndexType::DRAINAGE) ? 0 : 1;
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] arrayIndex=" << arrayIndex << std::endl;
+ }
+
+ // Match TableCapillaryPressure exactly (but skip the forward table call which passes Pc instead of S)
+ real64 capPresWater = phaseCapPressure[ipWater];
+ if constexpr (ENABLE_COMPUTEINV_PATH_DEBUG) {
+ std::cout << "[COMPUTEINV_PATH] Input Pc=" << capPresWater << std::endl;
+ std::cout << "[COMPUTEINV_PATH] phaseVolFraction[ipWater] before=" << phaseVolFraction[ipWater] << std::endl;
+ }
+ array1d< real64 > input( 1 );
+ input[0] = capPresWater;
+ auto inputSlice = input.toSliceConst();
+
+ constexpr bool ENABLE_COMPUTEINV_DEBUG = false;
+ if( ENABLE_COMPUTEINV_DEBUG )
+ {
+ std::cout << "[COMPUTEINV_DEBUG] Two-phase, mode=" << (mode == fields::cappres::ModeIndexType::DRAINAGE ? "DRAINAGE" : "IMBIBITION")
+ << ", arrayIndex=" << arrayIndex << std::endl;
+ std::cout << "[COMPUTEINV_DEBUG] Input Pc=" << capPresWater << std::endl;
+ std::cout << "[COMPUTEINV_DEBUG] Derivative before call=" << dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater] << std::endl;
+ }
+
+ // Use only the inverse table call (the forward table call in TableCapillaryPressure passes Pc instead of S, which is incorrect)
+ // The derivative array is already zeroed at the start of computeInv
+ // real64 dS_dPc_before = dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater];
+ real64 S_before_inv = phaseVolFraction[ipWater];
+ if( ENABLE_COMPUTEINV_DEBUG )
+ {
+ std::cout << "[COMPUTEINV_DEBUG] Two-phase DRAINAGE/IMBIBITION: Before inverse table call" << std::endl;
+ std::cout << " S_before=" << S_before_inv << std::endl;
+ std::cout << " Pc_input=" << capPresWater << std::endl;
+ std::cout << " arrayIndex=" << arrayIndex << std::endl;
+ std::cout << " inputSlice[0]=" << inputSlice[0] << std::endl;
+ std::cout << " wrapper.size()=" << m_inverseWettingNonWettingCapillaryPressureKernelWrappers.size() << std::endl;
+ }
+ real64 S_returned = m_inverseWettingNonWettingCapillaryPressureKernelWrappers[arrayIndex].compute(
+ inputSlice,
+ &(dPhaseCapPressure_dPhaseVolFrac)[ipWater][ipWater] );
+ phaseVolFraction[ipWater] = S_returned;
+ real64 dS_dPc_after = dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater];
+ real64 S_after_inv = phaseVolFraction[ipWater];
+
+ if( ENABLE_COMPUTEINV_DEBUG )
+ {
+ std::cout << "[COMPUTEINV_DEBUG] After inverse table call:" << std::endl;
+ std::cout << " S_returned=" << S_returned << std::endl;
+ std::cout << " S_after=" << S_after_inv << std::endl;
+ std::cout << " dS_dPc_after=" << dS_dPc_after << std::endl;
+ if( std::abs( S_after_inv ) < 1e-10 && capPresWater > 3000 && capPresWater < 100000 )
+ {
+ std::cout << "[COMPUTEINV_DEBUG] ERROR: Pc=" << capPresWater
+ << " is within valid range but inverse table returned S=0!" << std::endl;
+ std::cout << "[COMPUTEINV_DEBUG] This will cause zero Jacobian and Pc_int won't update!" << std::endl;
+ }
+ }
+
+ // Set non-wetting phase - match TableCapillaryPressure
+ if( ipGas >= 0 )
+ {
+ phaseVolFraction[ipGas] = 1.0 - phaseVolFraction[ipWater];
+ }
+ else if( ipOil >= 0 )
+ {
+ phaseVolFraction[ipOil] = 1.0 - phaseVolFraction[ipWater];
+ }
+ // Direct lookup complete, skip Newton-Raphson
+ }
+ else
+ {
+ constexpr bool ENABLE_TWOPHASE_SCANNINGINV_DEBUG = false;
+
+ // For scanning curves, use Newton-Raphson
+ real64 S_guess = phaseMaxHistoricalVolFraction[ipWater];
+ if( S_guess < minS || S_guess > maxS )
+ {
+ real64 const Smin = m_wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Smax = m_wettingCurve.drainageExtremaPhaseVolFraction;
+ S_guess = 0.5 * (Smin + Smax);
+ S_guess = LvArray::math::max( S_guess, minS );
+ S_guess = LvArray::math::min( S_guess, maxS );
+ }
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ std::cout << "[2P_SCAN_INV] Mode=" << static_cast< int >(mode)
+ << ", Pc_target=" << phaseCapPressure[ipWater]
+ << ", S_guess=" << S_guess
+ << ", S_minHist=" << phaseMinHistoricalVolFraction[ipWater]
+ << ", S_maxHist=" << phaseMaxHistoricalVolFraction[ipWater]
+ << ", Smin_curve=" << m_wettingCurve.oppositeBoundPhaseVolFraction
+ << ", Smax_curve=" << m_wettingCurve.drainageExtremaPhaseVolFraction
+ << std::endl;
+ }
+
+ // Precompute fixed parameters for scanning curves (these don't change during Newton-Raphson)
+ real64 precomputedScrt_water = -1.0;
+ real64 precomputedDenomF_water = 0.0;
+ real64 precomputedShy_water = -1.0;
+
+ // Precompute for scanning curves (Mode 2, Mode 3, or Mode 4)
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE ||
+ mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ real64 const Smin = m_wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Smax = m_wettingCurve.drainageExtremaPhaseVolFraction;
+ real64 const E = m_killoughCurvatureParamCapPres;
+
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // DRAINAGE_TO_IMBIBITION: Shy should be minimum historical (where drainage started)
+ precomputedShy_water = (phaseMinHistoricalVolFraction[ipWater] > Smin) ?
+ phaseMinHistoricalVolFraction[ipWater] : Smin;
+
+ // Compute Scrt for DRAINAGE_TO_IMBIBITION scanning curve (wetting phase)
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, precomputedShy_water,
+ m_landParam[ipWater],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ precomputedScrt_water = Scrt;
+ // For wetting curve, Scrt IS the max wetting saturation (Swma = Scrt)
+ real64 const Swma = 1. - (1. - Scrt);
+ // Compute denomF for DRAINAGE_TO_IMBIBITION: denomF = (1. / (Swma - Shy + E) - 1. / E)
+ precomputedDenomF_water = (1. / (Swma - precomputedShy_water + E) - 1. / E);
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // IMBIBITION_TO_DRAINAGE: Shy should be maximum historical (where imbibition started)
+ precomputedShy_water = (phaseMaxHistoricalVolFraction[ipWater] < Smax) ?
+ phaseMaxHistoricalVolFraction[ipWater] : Smax;
+
+ // Compute Scrt for IMBIBITION_TO_DRAINAGE scanning curve (wetting phase)
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, precomputedShy_water,
+ m_landParam[ipWater],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ precomputedScrt_water = Scrt;
+ // Compute denomF for IMBIBITION_TO_DRAINAGE: denomF = (1. / (Shy - Scrt + E) - 1. / E)
+ precomputedDenomF_water = (1. / (precomputedShy_water - Scrt + E) - 1. / E);
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ // Mode 4: IMBIBITION_TO_DRAINAGE_FROM_SCANNING
+ // H (first reversal point) should be minimum historical (where imbibition started)
+ // This is used to compute Scrt for Mode 4
+ real64 const H = (phaseMinHistoricalVolFraction[ipWater] > Smin) ?
+ phaseMinHistoricalVolFraction[ipWater] : Smin;
+
+ // Compute Scrt for Mode 4 based on H (first reversal point)
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_wettingCurve, H,
+ m_landParam[ipWater],
+ m_jerauldParam_a, m_jerauldParam_b,
+ Scrt );
+ precomputedScrt_water = Scrt;
+ // For Mode 4, precomputedShy is not used in the same way, but set it to H for consistency
+ precomputedShy_water = H;
+ // denomF is not used for Mode 4 (it solves quadratic instead), but set to 0 to indicate it's not applicable
+ precomputedDenomF_water = 0.0;
+ }
+ }
+
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ std::cout << "[2P_SCAN_INV] Precomputed: Shy=" << precomputedShy_water
+ << ", Scrt=" << precomputedScrt_water
+ << ", denomF=" << precomputedDenomF_water
+ << ", E=" << m_killoughCurvatureParamCapPres
+ << ", Somin=" << m_phaseIntermediateMinVolFraction
+ << std::endl;
+ // Evaluate Pc at a few points to see the curve shape
+ real64 const S_lo = precomputedShy_water;
+ // For wetting curve, Scrt IS the max wetting saturation (Swma = Scrt)
+ real64 const Swma = 1. - (1. - precomputedScrt_water);
+ std::cout << "[2P_SCAN_INV] Shy=" << S_lo << ", Swma=" << Swma << std::endl;
+ for( int probe = 0; probe <= 5; ++probe )
+ {
+ real64 S_probe = S_lo + (Swma - S_lo) * probe / 5.0;
+ S_probe = LvArray::math::max( minS, LvArray::math::min( maxS, S_probe ));
+ real64 pc_probe = this->computeCapillaryPressureForSaturation(
+ S_probe, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingNonWettingCapillaryPressureKernelWrappers,
+ m_wettingCurve, m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a, m_jerauldParam_b,
+ true, precomputedScrt_water, precomputedDenomF_water, precomputedShy_water );
+ std::cout << "[2P_SCAN_INV] S=" << S_probe << " -> Pc=" << pc_probe << std::endl;
+ }
+ }
+
+ real64 S_lo_bracket, S_hi_bracket;
+ real64 Swma_debug = -1.0;
+ bool degenerateBracket = false;
+ if( mode == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // Mode 2: scanning curve valid in [Shy, Swma]
+ // For wetting curve, Scrt IS the max wetting saturation (Swma = Scrt)
+ real64 const Swma = 1. - (1. - precomputedScrt_water);
+ Swma_debug = Swma;
+ S_lo_bracket = precomputedShy_water;
+ S_hi_bracket = Swma;
+ // Guard: if Swma <= Shy, the scanning curve has no valid range (degenerate case).
+ // Fall back to returning S = Shy directly.
+ if( Swma <= precomputedShy_water + 1e-12 )
+ {
+ degenerateBracket = true;
+ }
+ }
+ else if( mode == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE )
+ {
+ // Mode 3: scanning curve valid in [Scrt_end, Shy]
+ S_lo_bracket = precomputedScrt_water;
+ S_hi_bracket = precomputedShy_water;
+ // Guard: if Shy <= Scrt, degenerate case
+ if( precomputedShy_water <= precomputedScrt_water + 1e-12 )
+ {
+ degenerateBracket = true;
+ }
+ }
+ else
+ {
+ array1d< real64 > input_inv( 1 );
+ input_inv[0] = phaseCapPressure[ipWater];
+ auto inputSlice_inv = input_inv.toSliceConst();
+
+ real64 dS_dPc_dr_unused = 0.0, dS_dPc_im_unused = 0.0;
+ real64 S_dr = m_inverseWettingNonWettingCapillaryPressureKernelWrappers[ModeIndexType::DRAINAGE].compute(
+ inputSlice_inv, &dS_dPc_dr_unused );
+ real64 S_im = m_inverseWettingNonWettingCapillaryPressureKernelWrappers[ModeIndexType::IMBIBITION].compute(
+ inputSlice_inv, &dS_dPc_im_unused );
+ S_dr = LvArray::math::max( minS, LvArray::math::min( maxS, S_dr ));
+ S_im = LvArray::math::max( minS, LvArray::math::min( maxS, S_im ));
+ S_lo_bracket = LvArray::math::min( S_dr, S_im );
+ S_hi_bracket = LvArray::math::max( S_dr, S_im );
+ }
+
+ S_lo_bracket = LvArray::math::max( minS, S_lo_bracket );
+ S_hi_bracket = LvArray::math::min( maxS, S_hi_bracket );
+
+ // Ensure S_lo <= S_hi (safety: swap if somehow still inverted after clamping)
+ if( S_lo_bracket > S_hi_bracket )
+ {
+ real64 tmp = S_lo_bracket;
+ S_lo_bracket = S_hi_bracket;
+ S_hi_bracket = tmp;
+ }
+
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ std::cout << "[2P_SCAN_INV] Bracket: S_lo=" << S_lo_bracket
+ << ", S_hi=" << S_hi_bracket
+ << ", Shy=" << precomputedShy_water
+ << ", Swma=" << Swma_debug
+ << ", Scrt=" << precomputedScrt_water
+ << (degenerateBracket ? " DEGENERATE" : "")
+ << std::endl;
+ }
+
+ // Handle degenerate bracket: if Swma <= Shy (Mode 2) or Shy <= Scrt (Mode 3),
+ // the scanning curve has no valid range. Return S = Shy (the departure point).
+ // The Killough formula at S=Shy gives F=0, so Pc = Pc_dr(Shy), which is consistent
+ // with the drainage curve at that point.
+ real64 const Pc_target = phaseCapPressure[ipWater];
+
+ if( degenerateBracket )
+ {
+ // Return S = Shy (departure point).
+ // The Killough formula at Shy gives F=0, so Pc = Pc_dr(Shy), consistent with drainage.
+ phaseVolFraction[ipWater] = precomputedShy_water;
+ if( ipGas >= 0 )
+ {
+ phaseVolFraction[ipGas] = 1.0 - precomputedShy_water;
+ }
+ else if( ipOil >= 0 )
+ {
+ phaseVolFraction[ipOil] = 1.0 - precomputedShy_water;
+ }
+ // Use drainage table derivative at Shy → dS/dPc = 1/(dPc/dS)
+ real64 dpc_dS_shy = 0.0;
+ m_wettingNonWettingCapillaryPressureKernelWrappers[ModeIndexType::DRAINAGE].compute(
+ &precomputedShy_water, &dpc_dS_shy );
+ if( LvArray::math::abs( dpc_dS_shy ) > 1e-14 )
+ {
+ dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater] = 1.0 / dpc_dS_shy;
+ }
+ else
+ {
+ dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater] = 0.0;
+ }
+ constexpr bool ENABLE_SCANINV_SUMMARY_DEGEN = false;
+ if constexpr (ENABLE_SCANINV_SUMMARY_DEGEN) {
+ std::cout << "[SCAN_INV] mode=" << static_cast< int >(mode)
+ << " Pc_tgt=" << Pc_target
+ << " Shy=" << precomputedShy_water
+ << " S=" << precomputedShy_water
+ << " dS/dPc=" << dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater]
+ << " DEGENERATE_BRACKET"
+ << std::endl;
+ }
+ }
+
+ if( !degenerateBracket )
+ {
+ // Step 2: Evaluate Pc at bracket endpoints to determine sign of residual
+
+ // Helper macro-like inline evaluation (avoids lambda for GEOS_HOST_DEVICE compatibility)
+ #define EVAL_SCANNING_PC( S_eval ) \
+ this->computeCapillaryPressureForSaturation( \
+ (S_eval), mode, ipWater, \
+ phaseMinHistoricalVolFraction[ipWater], \
+ phaseMaxHistoricalVolFraction[ipWater], \
+ phaseMode2PeakVolFraction[ipWater], \
+ m_wettingNonWettingCapillaryPressureKernelWrappers, \
+ m_wettingCurve, m_nonWettingCurve, \
+ m_landParam[ipWater], \
+ m_phaseIntermediateMinVolFraction, \
+ m_killoughCurvatureParamCapPres, \
+ m_jerauldParam_a, m_jerauldParam_b, \
+ true, \
+ precomputedScrt_water, \
+ precomputedDenomF_water, \
+ precomputedShy_water )
+
+ real64 Pc_lo = EVAL_SCANNING_PC( S_lo_bracket );
+ real64 Pc_hi = EVAL_SCANNING_PC( S_hi_bracket );
+ real64 res_lo = Pc_lo - Pc_target;
+ real64 res_hi = Pc_hi - Pc_target;
+
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ std::cout << "[2P_SCAN_INV] Pc_target=" << Pc_target
+ << ", Pc_lo=" << Pc_lo << " (res=" << res_lo << ")"
+ << ", Pc_hi=" << Pc_hi << " (res=" << res_hi << ")" << std::endl;
+ }
+
+ // Early return: if the root is already at a bracket endpoint
+ // (i.e., Pc_target ≈ Pc_scan(Shy) or Pc_target ≈ Pc_scan(Swma)),
+ // return that endpoint directly. This avoids the bisection sign-test
+ // bug where res_lo ≈ 0 causes the update rule `residual * res_lo < 0`
+ // to take the wrong branch (0 * negative = 0, NOT < 0), pushing the
+ // bracket away from the root and converging to garbage.
+ bool skipBisection = false;
+ real64 S = 0.5 * (S_lo_bracket + S_hi_bracket); // default midpoint
+
+ if( LvArray::math::abs( res_lo ) < tol )
+ {
+ S = S_lo_bracket;
+ skipBisection = true;
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ std::cout << "[2P_SCAN_INV] Root at lower bracket endpoint: S=" << S
+ << ", res_lo=" << res_lo << std::endl;
+ }
+ }
+ else if( LvArray::math::abs( res_hi ) < tol )
+ {
+ S = S_hi_bracket;
+ skipBisection = true;
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ std::cout << "[2P_SCAN_INV] Root at upper bracket endpoint: S=" << S
+ << ", res_hi=" << res_hi << std::endl;
+ }
+ }
+
+ if( !skipBisection )
+ {
+ // Ensure bracket contains the root (res_lo and res_hi should have opposite signs)
+ // If not, Pc_target is at the boundary of the scanning curve.
+ // Clamp to the nearest endpoint (don't expand outside valid range).
+ if( res_lo * res_hi > 0 )
+ {
+ // Root not bracketed — Pc_target is at or beyond scanning curve boundary
+ // Return the endpoint with the smallest residual
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ std::cout << "[2P_SCAN_INV] Root not bracketed: res_lo=" << res_lo
+ << ", res_hi=" << res_hi << " — using nearest endpoint" << std::endl;
+ }
+ // Pick the S with smallest |residual| and skip bisection
+ if( LvArray::math::abs( res_lo ) < LvArray::math::abs( res_hi ))
+ {
+ S_hi_bracket = S_lo_bracket; // collapse bracket to lo
+ }
+ else
+ {
+ S_lo_bracket = S_hi_bracket; // collapse bracket to hi
+ }
+ }
+
+ // Step 3: Bisection (guaranteed convergence within bracket)
+ S = 0.5 * (S_lo_bracket + S_hi_bracket); // start at midpoint
+ constexpr integer maxBisectIter = 50; // 50 bisections give ~15 digits of precision
+
+ for( integer iter = 0; iter < maxBisectIter; ++iter )
+ {
+ real64 const pc_computed = EVAL_SCANNING_PC( S );
+ real64 const residual = pc_computed - Pc_target;
+
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ if( iter <= 3 || iter == maxBisectIter - 1 || LvArray::math::abs( residual ) < tol )
+ {
+ std::cout << "[2P_SCAN_INV] Bisect iter=" << iter
+ << ", S=" << S << ", Pc(S)=" << pc_computed
+ << ", residual=" << residual
+ << ", bracket=[" << S_lo_bracket << "," << S_hi_bracket << "]" << std::endl;
+ }
+ }
+
+ if( LvArray::math::abs( residual ) < tol )
+ {
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ std::cout << "[2P_SCAN_INV] Converged at iter=" << iter << ", S=" << S << std::endl;
+ }
+ break;
+ }
+
+ // Update bracket — use <= to correctly handle res_lo ≈ 0
+ // (when the root is very near S_lo, residual * res_lo ≈ 0
+ // and the < test would take the wrong branch)
+ if( residual * res_lo <= 0 )
+ {
+ S_hi_bracket = S;
+ res_hi = residual;
+ }
+ else
+ {
+ S_lo_bracket = S;
+ res_lo = residual;
+ }
+
+ // Bisection step
+ S = 0.5 * (S_lo_bracket + S_hi_bracket);
+
+ // Check if bracket is too small
+ if( S_hi_bracket - S_lo_bracket < 1e-12 )
+ {
+ break;
+ }
+ }
+ } // end if (!skipBisection)
+
+ #undef EVAL_SCANNING_PC
+
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ real64 pc_final_check = this->computeCapillaryPressureForSaturation(
+ S, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingNonWettingCapillaryPressureKernelWrappers,
+ m_wettingCurve, m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a, m_jerauldParam_b,
+ true, precomputedScrt_water, precomputedDenomF_water, precomputedShy_water );
+ std::cout << "[2P_SCAN_INV] FINAL: S=" << S
+ << ", Pc(S)=" << pc_final_check
+ << ", Pc_target=" << phaseCapPressure[ipWater]
+ << ", error=" << (pc_final_check - phaseCapPressure[ipWater]) << std::endl;
+ }
+
+ phaseVolFraction[ipWater] = S;
+ // Set non-wetting phase
+ if( ipGas >= 0 )
+ {
+ phaseVolFraction[ipGas] = 1.0 - S;
+ }
+ else if( ipOil >= 0 )
+ {
+ phaseVolFraction[ipOil] = 1.0 - S;
+ }
+
+ // Compute derivative dPc/dS at final S using finite difference
+ // (matching the three-phase scanning curve path)
+ {
+ real64 const dS_final_requested = 1e-6;
+ real64 S_pert_final = S + dS_final_requested;
+ if( S_pert_final > maxS )
+ {
+ S_pert_final = S - dS_final_requested; // backward difference if at upper bound
+ S_pert_final = LvArray::math::max( S_pert_final, minS );
+ }
+ real64 const dS_final = S_pert_final - S;
+ real64 const pc_final = this->computeCapillaryPressureForSaturation(
+ S, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingNonWettingCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ true, // isWettingPhase
+ precomputedScrt_water,
+ precomputedDenomF_water,
+ precomputedShy_water );
+ real64 const pc_pert_final = this->computeCapillaryPressureForSaturation(
+ S_pert_final, mode, ipWater,
+ phaseMinHistoricalVolFraction[ipWater],
+ phaseMaxHistoricalVolFraction[ipWater],
+ phaseMode2PeakVolFraction[ipWater],
+ m_wettingNonWettingCapillaryPressureKernelWrappers,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_landParam[ipWater],
+ m_phaseIntermediateMinVolFraction,
+ m_killoughCurvatureParamCapPres,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ true, // isWettingPhase
+ precomputedScrt_water,
+ precomputedDenomF_water,
+ precomputedShy_water );
+ real64 dpc_dS_final = 0.0;
+ if( LvArray::math::abs( dS_final ) > 1e-14 )
+ {
+ dpc_dS_final = (pc_pert_final - pc_final) / dS_final;
+ }
+ // computeInv must return dS/dPc (not dPc/dS), matching the inverse table convention.
+ // The local solver uses this as: dV/dPc = dV/dS * dS/dPc.
+ real64 const dS_dPc_final = (LvArray::math::abs( dpc_dS_final ) > 1e-14) ? (1.0 / dpc_dS_final) : 0.0;
+ dPhaseCapPressure_dPhaseVolFrac[ipWater][ipWater] = dS_dPc_final;
+ if constexpr (ENABLE_TWOPHASE_SCANNINGINV_DEBUG) {
+ std::cout << "[2P_SCAN_INV] dPc/dS=" << dpc_dS_final
+ << ", dS/dPc=" << dS_dPc_final
+ << ", Pc(S)=" << pc_final << ", Pc(S+dS)=" << pc_pert_final << std::endl;
+ }
+ // --- Concise one-line debug for scanning curve computeInv ---
+ constexpr bool ENABLE_SCANINV_SUMMARY = false;
+ if constexpr (ENABLE_SCANINV_SUMMARY) {
+ std::cout << "[SCAN_INV] mode=" << static_cast< int >(mode)
+ << " Pc_tgt=" << phaseCapPressure[ipWater]
+ << " Shy=" << precomputedShy_water
+ << " Swma=" << Swma_debug
+ << " S=" << S
+ << " dS/dPc=" << dS_dPc_final
+ << (skipBisection ? " SKIP_BISECT" : " BISECT")
+ << std::endl;
+ }
+ }
+ } // end if (!degenerateBracket)
+ } // End else block for scanning curves
+ }
+ }
+}
+
+/// kernel creation
+
+TableCapillaryPressureHysteresis::KernelWrapper TableCapillaryPressureHysteresis::createKernelWrapper()
+{
+
+ // we want to make sure that the wrappers are always up-to-date, so we recreate them everytime
+ createAllTableKernelWrappers();
+
+ // Validate that the arrays are properly populated
+ integer const numPhases = m_phaseNames.size();
+ if( numPhases == 2 )
+ {
+ GEOS_THROW_IF( m_wettingNonWettingCapillaryPressureKernelWrappers.size() != 2,
+ GEOS_FMT( "{}: Expected 2 kernel wrappers for two-phase flow, but got {}. "
+ "This usually means createAllTableKernelWrappers() failed to populate the arrays. "
+ "Check that table functions '{}' and '{}' exist and are properly defined.",
+ getFullName(),
+ m_wettingNonWettingCapillaryPressureKernelWrappers.size(),
+ m_drainageWettingNonWettingCapPresTableName,
+ m_imbibitionWettingNonWettingCapPresTableName.empty() ? m_drainageWettingNonWettingCapPresTableName : m_imbibitionWettingNonWettingCapPresTableName ),
+ InputError );
+ }
+ else if( numPhases == 3 )
+ {
+ GEOS_THROW_IF( m_wettingIntermediateCapillaryPressureKernelWrappers.size() != 2,
+ GEOS_FMT( "{}: Expected 2 wetting-intermediate kernel wrappers for three-phase flow, but got {}",
+ getFullName(),
+ m_wettingIntermediateCapillaryPressureKernelWrappers.size()),
+ InputError );
+ GEOS_THROW_IF( m_nonWettingIntermediateCapillaryPressureKernelWrappers.size() != 2,
+ GEOS_FMT( "{}: Expected 2 non-wetting-intermediate kernel wrappers for three-phase flow, but got {}",
+ getFullName(),
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers.size()),
+ InputError );
+ }
+
+ // Validate that m_phaseHasHysteresis is properly initialized
+ GEOS_THROW_IF( m_phaseHasHysteresis.size() != 2,
+ GEOS_FMT( "{}: m_phaseHasHysteresis must have size 2, but got {}",
+ getFullName(),
+ m_phaseHasHysteresis.size()),
+ InputError );
+
+ // Validate that the historical volume fraction arrays have been resized
+ // These arrays should be resized by resizeFields() before the KernelWrapper is used
+ // If they're empty, it means resizeFields() hasn't been called yet
+ GEOS_THROW_IF( m_phaseMaxHistoricalVolFraction.size( 0 ) == 0 || m_phaseMaxHistoricalVolFraction.size( 1 ) == 0,
+ GEOS_FMT( "{}: phaseMaxHistoricalVolFraction array has not been resized (size=[{}, {}]). "
+ "This usually means resizeFields() has not been called yet. "
+ "The arrays must be resized before the KernelWrapper can be used.",
+ getFullName(),
+ m_phaseMaxHistoricalVolFraction.size( 0 ),
+ m_phaseMaxHistoricalVolFraction.size( 1 )),
+ InputError );
+ GEOS_THROW_IF( m_phaseMinHistoricalVolFraction.size( 0 ) == 0 || m_phaseMinHistoricalVolFraction.size( 1 ) == 0,
+ GEOS_FMT( "{}: phaseMinHistoricalVolFraction array has not been resized (size=[{}, {}]). "
+ "This usually means resizeFields() has not been called yet. "
+ "The arrays must be resized before the KernelWrapper can be used.",
+ getFullName(),
+ m_phaseMinHistoricalVolFraction.size( 0 ),
+ m_phaseMinHistoricalVolFraction.size( 1 )),
+ InputError );
+ GEOS_THROW_IF( m_phaseMode2PeakVolFraction.size( 0 ) == 0 || m_phaseMode2PeakVolFraction.size( 1 ) == 0,
+ GEOS_FMT( "{}: phaseMode2PeakVolFraction array has not been resized (size=[{}, {}]). "
+ "This usually means resizeFields() has not been called yet. "
+ "The arrays must be resized before the KernelWrapper can be used.",
+ getFullName(),
+ m_phaseMode2PeakVolFraction.size( 0 ),
+ m_phaseMode2PeakVolFraction.size( 1 )),
+ InputError );
+
+ // then we create the actual TableRelativePermeabilityHysteresis::KernelWrapper
+ return KernelWrapper( m_wettingNonWettingCapillaryPressureKernelWrappers,
+ m_inverseWettingNonWettingCapillaryPressureKernelWrappers,
+ m_wettingIntermediateCapillaryPressureKernelWrappers,
+ m_inverseWettingIntermediateCapillaryPressureKernelWrappers,
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers,
+ m_inverseNonWettingIntermediateCapillaryPressureKernelWrappers,
+ m_phaseHasHysteresis,
+ m_landParam,
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ m_killoughCurvatureParamCapPres,
+ m_phaseIntermediateMinVolFraction,
+ m_wettingCurve,
+ m_nonWettingCurve,
+ m_phaseMinHistoricalVolFraction,
+ m_phaseMaxHistoricalVolFraction,
+ m_phaseMode2PeakVolFraction,
+ m_phaseTypes,
+ m_phaseOrder,
+ m_mode,
+ m_phaseTrappedVolFrac,
+ m_phaseCapPressure,
+ m_dPhaseCapPressure_dPhaseVolFrac );
+}
+
+void TableCapillaryPressureHysteresis::createAllTableKernelWrappers()
+{
+ using TPP = ThreePhasePairPhaseType;
+
+ FunctionManager const & functionManager = FunctionManager::getInstance();
+
+ integer const numPhases = m_phaseNames.size();
+
+ // Ensure m_phaseHasHysteresis is initialized before accessing it
+ // This can happen if createKernelWrapper is called before postProcessInput
+ if( m_phaseHasHysteresis.size() == 0 )
+ {
+ m_phaseHasHysteresis.resize( 2 );
+ if( numPhases == 2 )
+ {
+ m_phaseHasHysteresis[TPP::INTERMEDIATE_WETTING] =
+ (m_imbibitionWettingNonWettingCapPresTableName.empty() ||
+ m_imbibitionWettingNonWettingCapPresTableName == m_drainageWettingNonWettingCapPresTableName)
+ ? 0 : 1;
+ m_phaseHasHysteresis[TPP::INTERMEDIATE_NONWETTING] = m_phaseHasHysteresis[TPP::INTERMEDIATE_WETTING];
+ }
+ else if( numPhases == 3 )
+ {
+ m_phaseHasHysteresis[TPP::INTERMEDIATE_WETTING] =
+ (m_imbibitionWettingIntermediateCapPresTableName.empty() ||
+ m_imbibitionWettingIntermediateCapPresTableName == m_drainageWettingIntermediateCapPresTableName)
+ ? 0 : 1;
+ m_phaseHasHysteresis[TPP::INTERMEDIATE_NONWETTING] =
+ (m_imbibitionNonWettingIntermediateCapPresTableName.empty() ||
+ m_imbibitionNonWettingIntermediateCapPresTableName == m_drainageNonWettingIntermediateCapPresTableName)
+ ? 0 : 1;
+ }
+ }
+
+ // we want to make sure that the wrappers are always up-to-date, so we recreate them everytime
+
+ m_wettingNonWettingCapillaryPressureKernelWrappers.clear();
+ m_inverseWettingNonWettingCapillaryPressureKernelWrappers.clear();
+ m_wettingIntermediateCapillaryPressureKernelWrappers.clear();
+ m_inverseWettingIntermediateCapillaryPressureKernelWrappers.clear();
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers.clear();
+ m_inverseNonWettingIntermediateCapillaryPressureKernelWrappers.clear();
+ m_inverseTables.clear();
+
+ if( numPhases == 2 )
+ {
+ GEOS_THROW_IF( m_drainageWettingNonWettingCapPresTableName.empty(),
+ GEOS_FMT( "{}: drainageWettingNonWettingCapPressureTableName is empty for two-phase flow",
+ getFullName()),
+ InputError );
+
+ GEOS_THROW_IF( !functionManager.hasGroup( m_drainageWettingNonWettingCapPresTableName ),
+ GEOS_FMT( "{}: the table function named '{}' could not be found",
+ getFullName(),
+ m_drainageWettingNonWettingCapPresTableName ),
+ InputError );
+ TableFunction const & drainageCapPresTable = functionManager.getGroup< TableFunction >(
+ m_drainageWettingNonWettingCapPresTableName );
+ m_wettingNonWettingCapillaryPressureKernelWrappers.emplace_back(
+ drainageCapPresTable.createKernelWrapper());
+
+
+ string const & imbibitionTableName = m_phaseHasHysteresis[TPP::INTERMEDIATE_WETTING]
+ ? m_imbibitionWettingNonWettingCapPresTableName
+ : m_drainageWettingNonWettingCapPresTableName;
+ GEOS_THROW_IF( imbibitionTableName.empty(),
+ GEOS_FMT( "{}: imbibition table name is empty for two-phase flow",
+ getFullName()),
+ InputError );
+ GEOS_THROW_IF( !functionManager.hasGroup( imbibitionTableName ),
+ GEOS_FMT( "{}: the table function named '{}' could not be found",
+ getFullName(),
+ imbibitionTableName ),
+ InputError );
+ TableFunction const & imbibitionWettingCapPresTable = functionManager.getGroup< TableFunction >(
+ imbibitionTableName );
+ m_wettingNonWettingCapillaryPressureKernelWrappers.emplace_back(
+ imbibitionWettingCapPresTable.createKernelWrapper());
+
+ GEOS_THROW_IF( m_wettingNonWettingCapillaryPressureKernelWrappers.size() != 2,
+ GEOS_FMT( "{}: Expected 2 kernel wrappers after creation, but got {}",
+ getFullName(),
+ m_wettingNonWettingCapillaryPressureKernelWrappers.size()),
+ InputError );
+
+ // Create inverse tables for drainage and imbibition (for direct lookup in computeInv)
+ // Inverse for drainage (index 0)
+ auto const & drainageSatArrayView = drainageCapPresTable.getCoordinates()[0];
+ auto const & drainagePcArrayView = drainageCapPresTable.getValues();
+ std::vector< real64 > drainageSatVec( drainageSatArrayView.size());
+ std::vector< real64 > drainagePcVec( drainagePcArrayView.size());
+ std::copy( drainageSatArrayView.begin(), drainageSatArrayView.end(), drainageSatVec.begin());
+ std::copy( drainagePcArrayView.begin(), drainagePcArrayView.end(), drainagePcVec.begin());
+ // Reverse both arrays (if original Pc is decreasing in S)
+ std::reverse( drainagePcVec.begin(), drainagePcVec.end());
+ std::reverse( drainageSatVec.begin(), drainageSatVec.end());
+
+
+ auto inverseDrainageTable = std::make_shared< TableFunction >( "inverseDrainageCapPres", this );
+ real64_array invDrainagePcVec( drainagePcVec.size());
+ real64_array invDrainageSatVec( drainageSatVec.size());
+ std::copy( drainagePcVec.begin(), drainagePcVec.end(), invDrainagePcVec.data());
+ std::copy( drainageSatVec.begin(), drainageSatVec.end(), invDrainageSatVec.data());
+ array1d< real64_array > drainageCoordinates;
+ drainageCoordinates.emplace_back( std::move( invDrainagePcVec ));
+ std::vector< units::Unit > dimUnits = {units::Unknown};
+ inverseDrainageTable->setTableCoordinates( drainageCoordinates, dimUnits );
+ inverseDrainageTable->setTableValues( std::move( invDrainageSatVec ), units::Unknown );
+ inverseDrainageTable->setInterpolationMethod( TableFunction::InterpolationType::Linear );
+ m_inverseWettingNonWettingCapillaryPressureKernelWrappers.emplace_back(
+ inverseDrainageTable->createKernelWrapper());
+ m_inverseTables.emplace_back( std::move( inverseDrainageTable ));
+
+ // Inverse for imbibition (index 1)
+ auto const & imbibitionSatArrayView = imbibitionWettingCapPresTable.getCoordinates()[0];
+ auto const & imbibitionPcArrayView = imbibitionWettingCapPresTable.getValues();
+ std::vector< real64 > imbibitionSatVec( imbibitionSatArrayView.size());
+ std::vector< real64 > imbibitionPcVec( imbibitionPcArrayView.size());
+ std::copy( imbibitionSatArrayView.begin(), imbibitionSatArrayView.end(), imbibitionSatVec.begin());
+ std::copy( imbibitionPcArrayView.begin(), imbibitionPcArrayView.end(), imbibitionPcVec.begin());
+ // Reverse both arrays (if original Pc is decreasing in S)
+ std::reverse( imbibitionPcVec.begin(), imbibitionPcVec.end());
+ std::reverse( imbibitionSatVec.begin(), imbibitionSatVec.end());
+
+ auto inverseImbibitionTable = std::make_shared< TableFunction >( "inverseImbibitionCapPres", this );
+ real64_array invImbibitionPcVec( imbibitionPcVec.size());
+ real64_array invImbibitionSatVec( imbibitionSatVec.size());
+ std::copy( imbibitionPcVec.begin(), imbibitionPcVec.end(), invImbibitionPcVec.data());
+ std::copy( imbibitionSatVec.begin(), imbibitionSatVec.end(), invImbibitionSatVec.data());
+ array1d< real64_array > imbibitionCoordinates;
+ imbibitionCoordinates.emplace_back( std::move( invImbibitionPcVec ));
+ inverseImbibitionTable->setTableCoordinates( imbibitionCoordinates, dimUnits );
+ inverseImbibitionTable->setTableValues( std::move( invImbibitionSatVec ), units::Unknown );
+ inverseImbibitionTable->setInterpolationMethod( TableFunction::InterpolationType::Linear );
+ m_inverseWettingNonWettingCapillaryPressureKernelWrappers.emplace_back(
+ inverseImbibitionTable->createKernelWrapper());
+ m_inverseTables.emplace_back( std::move( inverseImbibitionTable ));
+
+ }
+ else if( numPhases == 3 )
+ {
+ TableFunction const & drainageWICapPres = functionManager.getGroup< TableFunction >(
+ m_drainageWettingIntermediateCapPresTableName );
+ m_wettingIntermediateCapillaryPressureKernelWrappers.emplace_back(
+ drainageWICapPres.createKernelWrapper());
+
+ TableFunction const & drainageNWICapPres = functionManager.getGroup< TableFunction >(
+ m_drainageNonWettingIntermediateCapPresTableName );
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers.emplace_back(
+ drainageNWICapPres.createKernelWrapper());
+
+ TableFunction const & imbibitionWICapPres = m_phaseHasHysteresis[TPP::INTERMEDIATE_WETTING]
+ ? functionManager.getGroup< TableFunction >(
+ m_imbibitionWettingIntermediateCapPresTableName )
+ : functionManager.getGroup< TableFunction >(
+ m_drainageWettingIntermediateCapPresTableName );
+ m_wettingIntermediateCapillaryPressureKernelWrappers.emplace_back(
+ imbibitionWICapPres.createKernelWrapper());
+
+ TableFunction const & imbibitionNWICapPres = m_phaseHasHysteresis[TPP::INTERMEDIATE_NONWETTING]
+ ? functionManager.getGroup< TableFunction >(
+ m_imbibitionNonWettingIntermediateCapPresTableName )
+ : functionManager.getGroup< TableFunction >(
+ m_drainageNonWettingIntermediateCapPresTableName );
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers.emplace_back(
+ imbibitionNWICapPres.createKernelWrapper());
+
+ // Create inverse tables for 3-phase (wetting-intermediate and non-wetting-intermediate)
+ // Inverse for wetting-intermediate drainage (index 0)
+ auto const & wiDrainageSatArrayView = drainageWICapPres.getCoordinates()[0];
+ auto const & wiDrainagePcArrayView = drainageWICapPres.getValues();
+ std::vector< real64 > wiDrainageSatVec( wiDrainageSatArrayView.size());
+ std::vector< real64 > wiDrainagePcVec( wiDrainagePcArrayView.size());
+ std::copy( wiDrainageSatArrayView.begin(), wiDrainageSatArrayView.end(), wiDrainageSatVec.begin());
+ std::copy( wiDrainagePcArrayView.begin(), wiDrainagePcArrayView.end(), wiDrainagePcVec.begin());
+ std::reverse( wiDrainagePcVec.begin(), wiDrainagePcVec.end());
+ std::reverse( wiDrainageSatVec.begin(), wiDrainageSatVec.end());
+
+ auto inverseWIDrainageTable = std::make_shared< TableFunction >( "inverseWIDrainageCapPres", this );
+ real64_array invWIDrainagePcVec( wiDrainagePcVec.size());
+ real64_array invWIDrainageSatVec( wiDrainageSatVec.size());
+ std::copy( wiDrainagePcVec.begin(), wiDrainagePcVec.end(), invWIDrainagePcVec.data());
+ std::copy( wiDrainageSatVec.begin(), wiDrainageSatVec.end(), invWIDrainageSatVec.data());
+ array1d< real64_array > wiDrainageCoordinates;
+ wiDrainageCoordinates.emplace_back( std::move( invWIDrainagePcVec ));
+ std::vector< units::Unit > dimUnits = {units::Unknown};
+ inverseWIDrainageTable->setTableCoordinates( wiDrainageCoordinates, dimUnits );
+ inverseWIDrainageTable->setTableValues( std::move( invWIDrainageSatVec ), units::Unknown );
+ inverseWIDrainageTable->setInterpolationMethod( TableFunction::InterpolationType::Linear );
+ m_inverseWettingIntermediateCapillaryPressureKernelWrappers.emplace_back(
+ inverseWIDrainageTable->createKernelWrapper());
+ m_inverseTables.emplace_back( std::move( inverseWIDrainageTable ));
+
+ // Inverse for wetting-intermediate imbibition (index 1)
+ auto const & wiImbibitionSatArrayView = imbibitionWICapPres.getCoordinates()[0];
+ auto const & wiImbibitionPcArrayView = imbibitionWICapPres.getValues();
+ std::vector< real64 > wiImbibitionSatVec( wiImbibitionSatArrayView.size());
+ std::vector< real64 > wiImbibitionPcVec( wiImbibitionPcArrayView.size());
+ std::copy( wiImbibitionSatArrayView.begin(), wiImbibitionSatArrayView.end(), wiImbibitionSatVec.begin());
+ std::copy( wiImbibitionPcArrayView.begin(), wiImbibitionPcArrayView.end(), wiImbibitionPcVec.begin());
+ std::reverse( wiImbibitionPcVec.begin(), wiImbibitionPcVec.end());
+ std::reverse( wiImbibitionSatVec.begin(), wiImbibitionSatVec.end());
+
+ auto inverseWIImbibitionTable = std::make_shared< TableFunction >( "inverseWIImbibitionCapPres", this );
+ real64_array invWIImbibitionPcVec( wiImbibitionPcVec.size());
+ real64_array invWIImbibitionSatVec( wiImbibitionSatVec.size());
+ std::copy( wiImbibitionPcVec.begin(), wiImbibitionPcVec.end(), invWIImbibitionPcVec.data());
+ std::copy( wiImbibitionSatVec.begin(), wiImbibitionSatVec.end(), invWIImbibitionSatVec.data());
+ array1d< real64_array > wiImbibitionCoordinates;
+ wiImbibitionCoordinates.emplace_back( std::move( invWIImbibitionPcVec ));
+ inverseWIImbibitionTable->setTableCoordinates( wiImbibitionCoordinates, dimUnits );
+ inverseWIImbibitionTable->setTableValues( std::move( invWIImbibitionSatVec ), units::Unknown );
+ inverseWIImbibitionTable->setInterpolationMethod( TableFunction::InterpolationType::Linear );
+ m_inverseWettingIntermediateCapillaryPressureKernelWrappers.emplace_back(
+ inverseWIImbibitionTable->createKernelWrapper());
+ m_inverseTables.emplace_back( std::move( inverseWIImbibitionTable ));
+
+ // Inverse for non-wetting-intermediate drainage (index 0)
+ auto const & nwiDrainageSatArrayView = drainageNWICapPres.getCoordinates()[0];
+ auto const & nwiDrainagePcArrayView = drainageNWICapPres.getValues();
+ std::vector< real64 > nwiDrainageSatVec( nwiDrainageSatArrayView.size());
+ std::vector< real64 > nwiDrainagePcVec( nwiDrainagePcArrayView.size());
+ std::copy( nwiDrainageSatArrayView.begin(), nwiDrainageSatArrayView.end(), nwiDrainageSatVec.begin());
+ std::copy( nwiDrainagePcArrayView.begin(), nwiDrainagePcArrayView.end(), nwiDrainagePcVec.begin());
+ std::reverse( nwiDrainagePcVec.begin(), nwiDrainagePcVec.end());
+ std::reverse( nwiDrainageSatVec.begin(), nwiDrainageSatVec.end());
+
+ auto inverseNWIDrainageTable = std::make_shared< TableFunction >( "inverseNWIDrainageCapPres", this );
+ real64_array invNWIDrainagePcVec( nwiDrainagePcVec.size());
+ real64_array invNWIDrainageSatVec( nwiDrainageSatVec.size());
+ std::copy( nwiDrainagePcVec.begin(), nwiDrainagePcVec.end(), invNWIDrainagePcVec.data());
+ std::copy( nwiDrainageSatVec.begin(), nwiDrainageSatVec.end(), invNWIDrainageSatVec.data());
+ array1d< real64_array > nwiDrainageCoordinates;
+ nwiDrainageCoordinates.emplace_back( std::move( invNWIDrainagePcVec ));
+ inverseNWIDrainageTable->setTableCoordinates( nwiDrainageCoordinates, dimUnits );
+ inverseNWIDrainageTable->setTableValues( std::move( invNWIDrainageSatVec ), units::Unknown );
+ inverseNWIDrainageTable->setInterpolationMethod( TableFunction::InterpolationType::Linear );
+ m_inverseNonWettingIntermediateCapillaryPressureKernelWrappers.emplace_back(
+ inverseNWIDrainageTable->createKernelWrapper());
+ m_inverseTables.emplace_back( std::move( inverseNWIDrainageTable ));
+
+ // Inverse for non-wetting-intermediate imbibition (index 1)
+ auto const & nwiImbibitionSatArrayView = imbibitionNWICapPres.getCoordinates()[0];
+ auto const & nwiImbibitionPcArrayView = imbibitionNWICapPres.getValues();
+ std::vector< real64 > nwiImbibitionSatVec( nwiImbibitionSatArrayView.size());
+ std::vector< real64 > nwiImbibitionPcVec( nwiImbibitionPcArrayView.size());
+ std::copy( nwiImbibitionSatArrayView.begin(), nwiImbibitionSatArrayView.end(), nwiImbibitionSatVec.begin());
+ std::copy( nwiImbibitionPcArrayView.begin(), nwiImbibitionPcArrayView.end(), nwiImbibitionPcVec.begin());
+ std::reverse( nwiImbibitionPcVec.begin(), nwiImbibitionPcVec.end());
+ std::reverse( nwiImbibitionSatVec.begin(), nwiImbibitionSatVec.end());
+
+ auto inverseNWIImbibitionTable = std::make_shared< TableFunction >( "inverseNWIImbibitionCapPres", this );
+ real64_array invNWIImbibitionPcVec( nwiImbibitionPcVec.size());
+ real64_array invNWIImbibitionSatVec( nwiImbibitionSatVec.size());
+ std::copy( nwiImbibitionPcVec.begin(), nwiImbibitionPcVec.end(), invNWIImbibitionPcVec.data());
+ std::copy( nwiImbibitionSatVec.begin(), nwiImbibitionSatVec.end(), invNWIImbibitionSatVec.data());
+ array1d< real64_array > nwiImbibitionCoordinates;
+ nwiImbibitionCoordinates.emplace_back( std::move( invNWIImbibitionPcVec ));
+ inverseNWIImbibitionTable->setTableCoordinates( nwiImbibitionCoordinates, dimUnits );
+ inverseNWIImbibitionTable->setTableValues( std::move( invNWIImbibitionSatVec ), units::Unknown );
+ inverseNWIImbibitionTable->setInterpolationMethod( TableFunction::InterpolationType::Linear );
+ m_inverseNonWettingIntermediateCapillaryPressureKernelWrappers.emplace_back(
+ inverseNWIImbibitionTable->createKernelWrapper());
+ m_inverseTables.emplace_back( std::move( inverseNWIImbibitionTable ));
+ }
+
+}
+
+///kernel ctor
+TableCapillaryPressureHysteresis::KernelWrapper::KernelWrapper(
+ arrayView1d< const TableFunction::KernelWrapper > const & wettingNonWettingCapillaryPressureKernelWrappers,
+ arrayView1d< const TableFunction::KernelWrapper > const & inverseWettingNonWettingCapillaryPressureKernelWrappers,
+ arrayView1d< const TableFunction::KernelWrapper > const & wettingIntermediateCapillaryPressureKernelWrappers,
+ arrayView1d< const TableFunction::KernelWrapper > const & inverseWettingIntermediateCapillaryPressureKernelWrappers,
+ arrayView1d< const TableFunction::KernelWrapper > const & nonWettingIntermediateCapillaryPressureKernelWrappers,
+ arrayView1d< const TableFunction::KernelWrapper > const & inverseNonWettingIntermediateCapillaryPressureKernelWrappers,
+ const arrayView1d< const geos::integer > & phaseHasHysteresis,
+ const arrayView1d< const geos::real64 > & landParam,
+ const real64 & jerauldParam_a,
+ const real64 & jerauldParam_b,
+ const real64 & killoughCurvaturePcParam,
+ const geos::real64 & phaseIntermediateMinVolFraction,
+ const KilloughHysteresis::HysteresisCurve & wettingCurve,
+ const KilloughHysteresis::HysteresisCurve & nonWettingCurve,
+ const arrayView2d< const geos::real64, compflow::USD_PHASE > & phaseMinHistoricalVolFraction,
+ const arrayView2d< const geos::real64, compflow::USD_PHASE > & phaseMaxHistoricalVolFraction,
+ arrayView2d< geos::real64, compflow::USD_PHASE > & phaseMode2PeakVolFraction,
+ arrayView1d< integer const > const & phaseTypes,
+ arrayView1d< integer const > const & phaseOrder,
+ arrayView1d< integer > const & mode,
+ arrayView3d< real64, cappres::USD_CAPPRES > const & phaseTrapped,
+ const arrayView3d< geos::real64, relperm::USD_RELPERM > & phaseCapPressure,
+ const arrayView4d< geos::real64, relperm::USD_RELPERM_DS > & dPhaseCapPressure_dPhaseVolFrac )
+ :
+ CapillaryPressureBaseUpdate( phaseTypes,
+ phaseOrder,
+ phaseTrapped,
+ phaseCapPressure,
+ dPhaseCapPressure_dPhaseVolFrac ),
+ m_wettingNonWettingCapillaryPressureKernelWrappers( wettingNonWettingCapillaryPressureKernelWrappers ),
+ m_inverseWettingNonWettingCapillaryPressureKernelWrappers( inverseWettingNonWettingCapillaryPressureKernelWrappers ),
+ m_wettingIntermediateCapillaryPressureKernelWrappers(
+ wettingIntermediateCapillaryPressureKernelWrappers ),
+ m_inverseWettingIntermediateCapillaryPressureKernelWrappers( inverseWettingIntermediateCapillaryPressureKernelWrappers ),
+ m_nonWettingIntermediateCapillaryPressureKernelWrappers(
+ nonWettingIntermediateCapillaryPressureKernelWrappers ),
+ m_inverseNonWettingIntermediateCapillaryPressureKernelWrappers( inverseNonWettingIntermediateCapillaryPressureKernelWrappers ),
+ m_phaseHasHysteresis( phaseHasHysteresis ),
+ m_landParam( landParam ),
+ m_jerauldParam_a( jerauldParam_a ),
+ m_jerauldParam_b( jerauldParam_b ),
+ m_killoughCurvatureParamCapPres( killoughCurvaturePcParam ),
+ m_phaseIntermediateMinVolFraction( phaseIntermediateMinVolFraction ),
+ m_wettingCurve( wettingCurve ),
+ m_nonWettingCurve( nonWettingCurve ),
+ m_phaseMinHistoricalVolFraction( phaseMinHistoricalVolFraction ),
+ m_phaseMaxHistoricalVolFraction( phaseMaxHistoricalVolFraction ),
+ m_phaseMode2PeakVolFraction( phaseMode2PeakVolFraction ),
+ m_mode( mode ) {}
+
+REGISTER_CATALOG_ENTRY( ConstitutiveBase, TableCapillaryPressureHysteresis, std::string const &, Group * const )
+
+} // namespace constitutive
+} // namespace geos
diff --git a/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHysteresis.hpp b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHysteresis.hpp
new file mode 100644
index 00000000000..efb28c73be2
--- /dev/null
+++ b/src/coreComponents/constitutive/capillaryPressure/TableCapillaryPressureHysteresis.hpp
@@ -0,0 +1,756 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University
+ * Copyright (c) 2018-2020 TotalEnergies
+ * Copyright (c) 2019- GEOSX Contributors
+ * All rights reserved
+ *
+ * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+
+
+#ifndef GEOS_CONSTITUTIVE_TABLECAPILLARYPRESSUREHYSTERESIS_HPP
+#define GEOS_CONSTITUTIVE_TABLECAPILLARYPRESSUREHYSTERESIS_HPP
+
+#include "constitutive/capillaryPressure/CapillaryPressureBase.hpp"
+#include "functions/TableFunction.hpp"
+
+#include "constitutive/KilloughHysteresis.hpp"
+#include "CapillaryPressureFields.hpp"
+#include "common/DataLayouts.hpp"
+
+namespace geos
+{
+
+
+namespace constitutive
+{
+
+class TableCapillaryPressureHysteresis : public CapillaryPressureBase
+{
+// /// useful constant
+// static constexpr real64 CAP_INF = 1e9;
+//// std::numeric_limits< real64 >::max();
+// static constexpr real64 CAP_INF_DERIV = 1e9;
+//// std::numeric_limits< real64 >::max();
+
+ typedef fields::cappres::ModeIndexType ModeIndexType;
+
+public:
+
+ /// order of the phase properties for three-phase flow
+ struct ThreePhasePairPhaseType
+ {
+ enum : integer
+ {
+ INTERMEDIATE_WETTING = 0, ///< index for intermediate-wetting
+ INTERMEDIATE_NONWETTING = 1 ///< index for intermediate-non-wetting
+ };
+ };
+
+
+ TableCapillaryPressureHysteresis( std::string const & name,
+ dataRepository::Group * const parent );
+
+ static std::string catalogName() { return "TableCapillaryPressureHysteresis"; }
+
+ virtual string getCatalogName() const override { return catalogName(); }
+
+ ///Kernel
+ class KernelWrapper final : public CapillaryPressureBaseUpdate
+ {
+public:
+
+ KernelWrapper(
+ arrayView1d< TableFunction::KernelWrapper const > const & wettingNonWettingCapillaryPressureKernelWrappers,
+ arrayView1d< TableFunction::KernelWrapper const > const & inverseWettingNonWettingCapillaryPressureKernelWrappers,
+ arrayView1d< TableFunction::KernelWrapper const > const & wettingIntermediateCapillaryPressureKernelWrappers,
+ arrayView1d< TableFunction::KernelWrapper const > const & inverseWettingIntermediateCapillaryPressureKernelWrappers,
+ arrayView1d< TableFunction::KernelWrapper const > const & nonWettingIntermediateCapillaryPressureKernelWrappers,
+ arrayView1d< TableFunction::KernelWrapper const > const & inverseNonWettingIntermediateCapillaryPressureKernelWrappers,
+ arrayView1d< integer const > const & phaseHasHysteresis,
+ arrayView1d< real64 const > const & landParam,
+ real64 const & jerauldParam_a,
+ real64 const & jerauldParam_b,
+ real64 const & killoughCurvaturePcParameter,
+ real64 const & phaseIntermediateMinVolFraction,
+ KilloughHysteresis::HysteresisCurve const & wettingCurve,
+ KilloughHysteresis::HysteresisCurve const & nonWettingCurve,
+ arrayView2d< real64 const, compflow::USD_PHASE > const & phaseMinHistoricalVolFraction,
+ arrayView2d< real64 const, compflow::USD_PHASE > const & phaseMaxHistoricalVolFraction,
+ arrayView2d< real64, compflow::USD_PHASE > & phaseMode2PeakVolFraction,
+ arrayView1d< integer const > const & phaseTypes,
+ arrayView1d< integer const > const & phaseOrder,
+ arrayView1d< integer > const & mode,
+ arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac,
+ arrayView3d< real64, relperm::USD_RELPERM > const & phaseCapPressure,
+ arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseCapPressure_dPhaseVolFrac );
+
+ //actual workers
+ GEOS_HOST_DEVICE
+ void computeBoundCapillaryPressure( TableFunction::KernelWrapper const & drainageCapPressureWrapper,
+ real64 const & phaseVolFraction,
+ real64 & phaseCapPressure,
+ real64 & dPhaseCapPressure_dPhaseVolFrac ) const;
+
+ GEOS_HOST_DEVICE
+ void
+ computeImbibitionWettingCapillaryPressure(
+ const arrayView1d< const TableFunction::KernelWrapper > & wettingKernelWapper,
+ const KilloughHysteresis::HysteresisCurve & wettingCurve,
+ const KilloughHysteresis::HysteresisCurve & nonWettingCurve,
+ const geos::real64 & landParam,
+ const geos::real64 & phaseVolFraction,
+ const geos::real64 & phaseMinHistoricalVolFraction,
+ const geos::real64 & phaseMaxHistoricalVolFraction,
+ const geos::real64 & phaseMode2PeakVolFraction,
+ geos::real64 & phaseTrappedVolFrac,
+ geos::real64 & phaseCapPressure,
+ geos::real64 & dPhaseCapPressure_dPhaseVolFrac,
+ const ModeIndexType & mode ) const;
+
+ //two phase flow overload
+ GEOS_HOST_DEVICE
+ void
+ computeImbibitionWettingCapillaryPressure(
+ const arrayView1d< const TableFunction::KernelWrapper > & wettingKernelWapper,
+ const KilloughHysteresis::HysteresisCurve & wettingCurve,
+ const geos::real64 & landParam,
+ const geos::real64 & phaseVolFraction,
+ const geos::real64 & phaseMinHistoricalVolFraction,
+ const geos::real64 & phaseMaxHistoricalVolFraction,
+ const geos::real64 & phaseMode2PeakVolFraction,
+ geos::real64 & phaseTrappedVolFrac,
+ geos::real64 & phaseCapPressure,
+ geos::real64 & dPhaseCapPressure_dPhaseVolFrac,
+ const ModeIndexType & mode ) const;
+
+ GEOS_HOST_DEVICE
+ void
+ computeImbibitionNonWettingCapillaryPressure(
+ const arrayView1d< const TableFunction::KernelWrapper > & nonWettingKernelWrapper,
+ const KilloughHysteresis::HysteresisCurve & nonWettingCurve,
+ const KilloughHysteresis::HysteresisCurve & wettingCurve,
+ const geos::real64 & landParam,
+ const geos::real64 & phaseVolFraction,
+ const geos::real64 & phaseMaxHistoricalVolFraction,
+ geos::real64 & phaseTrappedVolFrac,
+ geos::real64 & phaseCapPressure,
+ geos::real64 & dPhaseCapPressure_dPhaseVolFrac,
+ const ModeIndexType & mode ) const;
+
+ //2phase flow overload
+ GEOS_HOST_DEVICE
+ void
+ computeImbibitionNonWettingCapillaryPressure(
+ const arrayView1d< const TableFunction::KernelWrapper > & nonWettingKernelWrapper,
+ const KilloughHysteresis::HysteresisCurve & nonWettingCurve,
+ const geos::real64 & landParam,
+ const geos::real64 & phaseVolFraction,
+ const geos::real64 & phaseMaxHistoricalVolFraction,
+ geos::real64 & phaseTrappedVolFrac,
+ geos::real64 & phaseCapPressure,
+ geos::real64 & dPhaseCapPressure_dPhaseVolFrac,
+ const ModeIndexType & mode ) const;
+
+
+
+ //wrapper call wrt number of phase
+ GEOS_HOST_DEVICE
+ void computeTwoPhaseWetting( integer const ipWetting,
+ integer const ipNonWetting,
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const,
+ compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction,
+ arraySlice1d< real64 const,
+ compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction,
+ arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac,
+ arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseCapPressure,
+ arraySlice2d< real64,
+ relperm::USD_RELPERM_DS - 2 > const & dPhaseCapPressure_dPhaseVolFrac,
+ ModeIndexType & mode,
+ arraySlice1d< real64, compflow::USD_PHASE - 1 > & phaseMode2PeakVolFraction ) const;
+
+
+ GEOS_HOST_DEVICE
+ void computeTwoPhaseNonWetting( integer const ipWetting,
+ integer const ipNonWetting,
+ arraySlice1d< real64 const,
+ compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const,
+ compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction,
+ arraySlice1d< real64 const,
+ compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction,
+ arraySlice1d< real64,
+ relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac,
+ arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseCapPressure,
+ arraySlice2d< real64, relperm::USD_RELPERM_DS -
+ 2 > const & dPhaseCapPressure_dPhaseVolFrac,
+ ModeIndexType & mode ) const;
+
+ GEOS_HOST_DEVICE
+ void computeThreePhase( integer const ipWetting,
+ integer const ipInter,
+ integer const ipNonWetting,
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const,
+ compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction,
+ arraySlice1d< real64 const,
+ compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction,
+ arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseTrappedVolFrac,
+ arraySlice1d< real64, relperm::USD_RELPERM - 2 > const & phaseCapPressure,
+ arraySlice2d< real64,
+ relperm::USD_RELPERM_DS - 2 > const & dPhaseCapPressure_dPhaseVolFrac,
+ ModeIndexType & mode,
+ arraySlice1d< real64, compflow::USD_PHASE - 1 > & phaseMode2PeakVolFraction ) const;
+
+ //uppermost call-wrappers
+ // Standard 3-argument compute method for compatibility with InverseCapillaryPressure
+ GEOS_HOST_DEVICE
+ void compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseCapPressure,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPressure_dPhaseVolFrac ) const;
+
+ GEOS_HOST_DEVICE
+ virtual void compute( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const,
+ compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction,
+ arraySlice1d< real64 const,
+ compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction,
+ arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseTrappedVolFrac,
+ arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseCapPressure,
+ arraySlice2d< real64,
+ cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPressure_dPhaseVolFrac,
+ ModeIndexType & mode,
+ arraySlice1d< real64, compflow::USD_PHASE - 1 > & phaseMode2PeakVolFraction ) const;
+
+ GEOS_HOST_DEVICE
+ virtual void update( localIndex const k,
+ localIndex const q,
+ arraySlice1d< real64 const,
+ compflow::USD_PHASE - 1 > const & phaseVolFraction ) const override;
+
+ /**
+ * @brief Compute phase volume fraction from capillary pressure (inverse operation).
+ * @param phaseVolFraction [out] Computed phase volume fractions
+ * @param phaseMaxHistoricalVolFraction [in] Maximum historical phase volume fractions
+ * @param phaseMinHistoricalVolFraction [in] Minimum historical phase volume fractions
+ * @param phaseTrappedVolFrac [in] Trapped phase volume fractions
+ * @param phaseCapPressure [in] Target capillary pressures (input)
+ * @param dPhaseCapPressure_dPhaseVolFrac [out] Derivatives of capillary pressure w.r.t. phase volume fraction
+ * @param mode [in] Hysteresis mode (DRAINAGE, IMBIBITION, DRAINAGE_TO_IMBIBITION, IMBIBITION_TO_DRAINAGE)
+ *
+ * Uses Newton-Raphson iteration to invert the capillary pressure function.
+ */
+ GEOS_HOST_DEVICE
+ void computeInv( arraySlice1d< real64, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction,
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction,
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMode2PeakVolFraction,
+ arraySlice1d< real64 const, cappres::USD_CAPPRES - 2 > const & phaseTrappedVolFrac,
+ arraySlice1d< real64 const, cappres::USD_CAPPRES - 2 > const & phaseCapPressure,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPressure_dPhaseVolFrac,
+ fields::cappres::ModeIndexType const & mode ) const;
+
+ /**
+ * @brief Evaluate the raw drainage or imbibition table at a given saturation,
+ * bypassing the hysteresis mode-transition logic in compute().
+ * @param tableIdx Table index (0 = DRAINAGE, 1 = IMBIBITION)
+ * @param phaseVolFraction Phase volume fraction to evaluate at
+ * @param phaseCapPressure [out] Capillary pressure from the table
+ * @param dPhaseCapPressure_dPhaseVolFrac [out] Derivative of Pc w.r.t. S
+ */
+ GEOS_HOST_DEVICE
+ void computeRawTablePc( integer const tableIdx,
+ real64 const & phaseVolFraction,
+ real64 & phaseCapPressure,
+ real64 & dPhaseCapPressure_dPhaseVolFrac ) const
+ {
+ computeBoundCapillaryPressure(
+ m_wettingNonWettingCapillaryPressureKernelWrappers[tableIdx],
+ phaseVolFraction, phaseCapPressure, dPhaseCapPressure_dPhaseVolFrac );
+ }
+
+ /**
+ * @brief Compute the actual Pc range [Pc_lo, Pc_hi] for a scanning curve.
+ *
+ * For Mode 2 (DRAINAGE_TO_IMBIBITION):
+ * Pc_hi = Pc_drainage(Shy) (departure point)
+ * Pc_lo = Pc_imbibition(Swma) (endpoint, where F=1)
+ * For Mode 3 (IMBIBITION_TO_DRAINAGE):
+ * Pc_lo = Pc_imbibition(Shy) (departure point)
+ * Pc_hi = Pc_drainage(Scrt) (endpoint, where F=1)
+ *
+ * @param phaseMinHistVolFrac Minimum historical volume fraction (Shy for Mode 2)
+ * @param phaseMaxHistVolFrac Maximum historical volume fraction (Shy for Mode 3)
+ * @param mode Hysteresis mode
+ * @param Pc_lo [out] Lower bound of scanning curve Pc range
+ * @param Pc_hi [out] Upper bound of scanning curve Pc range
+ */
+ GEOS_HOST_DEVICE
+ void computeScanningCurvePcRange( real64 const phaseMinHistVolFrac,
+ real64 const phaseMaxHistVolFrac,
+ ModeIndexType const mode,
+ real64 & Pc_lo,
+ real64 & Pc_hi ) const
+ {
+ integer const ipWater = 0;
+ real64 dPc_dummy;
+
+ if( mode == ModeIndexType::DRAINAGE_TO_IMBIBITION )
+ {
+ // Shy = min historical saturation (departure from drainage)
+ real64 const Smin_curve = m_wettingCurve.oppositeBoundPhaseVolFraction;
+ real64 const Shy = LvArray::math::max( phaseMinHistVolFrac, Smin_curve );
+
+ // Compute Scrt (trapped saturation) from Land model
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction(
+ m_wettingCurve, Shy, m_landParam[ipWater],
+ m_jerauldParam_a, m_jerauldParam_b, Scrt );
+
+ // For wetting phase, Swma = Scrt (= 1 - (1 - Scrt))
+ real64 const Swma = Scrt;
+
+ // Pc_hi = Pc_drainage(Shy) — departure point, highest Pc on scanning curve
+ computeRawTablePc( 0 /* drainage */, Shy, Pc_hi, dPc_dummy );
+
+ // Pc_lo = Pc_imbibition(Swma) — endpoint where F=1, lowest Pc on scanning curve
+ computeRawTablePc( 1 /* imbibition */, Swma, Pc_lo, dPc_dummy );
+ }
+ else if( mode == ModeIndexType::IMBIBITION_TO_DRAINAGE ||
+ mode == ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ // Shy = max historical saturation (departure from imbibition)
+ real64 const Smax_curve = m_wettingCurve.drainageExtremaPhaseVolFraction;
+ real64 const Shy = LvArray::math::min( phaseMaxHistVolFrac, Smax_curve );
+
+ // Compute Scrt
+ real64 Scrt = 0.0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction(
+ m_wettingCurve, Shy, m_landParam[ipWater],
+ m_jerauldParam_a, m_jerauldParam_b, Scrt );
+
+ // Pc_lo = Pc_imbibition(Shy) — departure point, lowest Pc on scanning curve
+ computeRawTablePc( 1 /* imbibition */, Shy, Pc_lo, dPc_dummy );
+
+ // Pc_hi = Pc_drainage(Scrt) — endpoint where F=1, highest Pc on scanning curve
+ computeRawTablePc( 0 /* drainage */, Scrt, Pc_hi, dPc_dummy );
+ }
+ else
+ {
+ // Fallback: use raw table full range
+ computeRawTablePc( 0 /* drainage */, 0.0, Pc_hi, dPc_dummy );
+ computeRawTablePc( 1 /* imbibition */, 1.0, Pc_lo, dPc_dummy );
+ }
+
+ // Ensure Pc_lo <= Pc_hi
+ if( Pc_lo > Pc_hi )
+ {
+ real64 tmp = Pc_lo;
+ Pc_lo = Pc_hi;
+ Pc_hi = tmp;
+ }
+ }
+
+private:
+
+ /**
+ * @brief Helper function to compute Pc(S) for given S, mode, and historical values.
+ * @param S Phase volume fraction
+ * @param mode Hysteresis mode
+ * @param ipPhase Phase index
+ * @param phaseMinHistoricalVolFraction Minimum historical volume fraction
+ * @param phaseMaxHistoricalVolFraction Maximum historical volume fraction
+ * @param capPresKernelWrappers Capillary pressure kernel wrappers
+ * @param wettingCurve Wetting curve data
+ * @param nonWettingCurve Non-wetting curve data
+ * @param landParam Land parameter
+ * @param phaseIntermediateMinVolFraction Intermediate phase minimum volume fraction
+ * @param killoughCurvatureParam Killough curvature parameter
+ * @param jerauldParam_a Jerauld parameter a
+ * @param jerauldParam_b Jerauld parameter b
+ * @param isWettingPhase Whether this is the wetting phase
+ * @param precomputedScrt Precomputed trapped critical saturation (optional, use -1.0 to compute)
+ * @param precomputedDenomF Precomputed denominator for F calculation (optional, use 0.0 to compute)
+ * @param precomputedShy Precomputed historical saturation Shy (optional, use -1.0 to compute)
+ * @return Computed capillary pressure
+ *
+ * Used for Newton-Raphson inversion in computeInv.
+ * If precomputed values are provided (precomputedScrt >= 0, precomputedDenomF != 0, precomputedShy >= 0),
+ * they will be used instead of recomputing them.
+ */
+ GEOS_HOST_DEVICE
+ real64 computeCapillaryPressureForSaturation(
+ real64 const S,
+ fields::cappres::ModeIndexType const & mode,
+ integer const ipPhase,
+ real64 const & phaseMinHistoricalVolFraction,
+ real64 const & phaseMaxHistoricalVolFraction,
+ real64 const & phaseMode2PeakVolFraction,
+ arrayView1d< TableFunction::KernelWrapper const > const & capPresKernelWrappers,
+ KilloughHysteresis::HysteresisCurve const & wettingCurve,
+ KilloughHysteresis::HysteresisCurve const & nonWettingCurve,
+ real64 const & landParam,
+ real64 const & phaseIntermediateMinVolFraction,
+ real64 const & killoughCurvatureParam,
+ real64 const & jerauldParam_a,
+ real64 const & jerauldParam_b,
+ bool const isWettingPhase,
+ real64 const precomputedScrt = -1.0,
+ real64 const precomputedDenomF = 0.0,
+ real64 const precomputedShy = -1.0 ) const;
+
+ static constexpr real64 flowReversalBuffer = KilloughHysteresis::flowReversalBuffer;
+// ModeIndexType& m_mode;
+
+ //2p
+ arrayView1d< TableFunction::KernelWrapper const > const m_wettingNonWettingCapillaryPressureKernelWrappers;
+ arrayView1d< TableFunction::KernelWrapper const > const m_inverseWettingNonWettingCapillaryPressureKernelWrappers;
+ //3p
+ arrayView1d< TableFunction::KernelWrapper const > const m_wettingIntermediateCapillaryPressureKernelWrappers;
+ arrayView1d< TableFunction::KernelWrapper const > const m_inverseWettingIntermediateCapillaryPressureKernelWrappers;
+ arrayView1d< TableFunction::KernelWrapper const > const m_nonWettingIntermediateCapillaryPressureKernelWrappers;
+ arrayView1d< TableFunction::KernelWrapper const > const m_inverseNonWettingIntermediateCapillaryPressureKernelWrappers;
+
+ ///Land Coeff
+ arrayView1d< integer const > m_phaseHasHysteresis;
+ arrayView1d< real64 const > m_landParam;
+
+ /// Parameter a introduced by Jerauld in the Land model
+ const real64 m_jerauldParam_a;
+
+ /// Parameter b introduced by Jerauld in the Land model
+ const real64 m_jerauldParam_b;
+
+ /// Curvature parameter in Killough wetting phase hysteresis (enpoints curvatures)
+ const real64 m_killoughCurvatureParamCapPres;
+
+ /// needed in 3p-wetting hysteresis as we need to get the max accessible pore space
+ real64 const m_phaseIntermediateMinVolFraction;
+
+ KilloughHysteresis::HysteresisCurve const m_wettingCurve;
+ KilloughHysteresis::HysteresisCurve const m_nonWettingCurve;
+
+ /// Minimum historical phase volume fraction for each phase
+ arrayView2d< real64 const, compflow::USD_PHASE > m_phaseMinHistoricalVolFraction;
+
+ /// Maximum historical phase volume fraction for each phase
+ arrayView2d< real64 const, compflow::USD_PHASE > m_phaseMaxHistoricalVolFraction;
+
+ /// Peak saturation reached during Mode 2 (DRAINAGE_TO_IMBIBITION) for each phase (mutable for updates)
+ arrayView2d< real64, compflow::USD_PHASE > m_phaseMode2PeakVolFraction;
+
+ // Drainage / Imbibition flags cellwise
+ arrayView1d< ModeIndexType > m_mode;
+
+ };
+
+ /**
+ * @brief Create an update kernel wrapper.
+ * @return the wrapper
+ */
+ KernelWrapper createKernelWrapper();
+
+ //might need it to be virtual one level higher --> from Killough/Hysteresis common class
+ virtual void saveConvergedPhaseVolFractionState(
+ arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFraction ) const override;
+
+
+ struct viewKeyStruct : CapillaryPressureBase::viewKeyStruct
+ {
+
+
+ ///Land Coeff
+ static constexpr char const *landParameterString() { return "landParameter"; }
+
+ ///flag
+ static constexpr char const *phaseHasHysteresisString() { return "phaseHasHysteresis"; }
+
+ ///and packed curves data struct
+ static constexpr char const *wettingCurveString() { return "wettingCurve"; };
+
+ static constexpr char const *nonWettingCurveString() { return "nonWettingCurve"; };
+
+
+ ///tables and assoc. wrappers
+ //2phase
+ static constexpr char const *
+ drainageWettingNonWettingCapPresTableNameString() { return "drainageWettingNonWettingCapPressureTableName"; }
+
+ static constexpr char const *
+ imbibitionWettingNonWettingCapPresTableNameString() { return "imbibitionWettingNonWettingCapPressureTableName"; }
+
+ //3phase
+ static constexpr char const *
+ drainageWettingIntermediateCapPresTableNameString() { return "drainageWettingIntermediateCapPressureTableName"; }
+
+ static constexpr char const *
+ drainageNonWettingIntermediateCapPresTableNameString() { return "drainageNonWettingIntermediateCapPressureTableName"; }
+
+ static constexpr char const *
+ imbibitionWettingIntermediateCapPresTableNameString() { return "imbibitionWettingIntermediateCapPressureTableName"; }
+
+ static constexpr char const *
+ imbibitionNonWettingIntermediateCapPresTableNameString() { return "imbibitionNonWettingIntermediateCapPressureTableName"; }
+
+ static constexpr char const *
+ wettingNonWettingCapillaryPressureKernelWrappersString() { return "wettingNonWettingCapillaryPressureKernelWrappers"; }
+
+ static constexpr char const *
+ wettingIntermediateCapillaryPressureKernelWrappersString() { return "wettingIntermediateCapillaryPressureKernelWrappers"; }
+
+ static constexpr char const *
+ nonWettingIntermediateCapillaryPressureKernelWrappersString() { return "nonWettingIntermediateCapillaryPressureKernelWrappers"; }
+
+ //misc
+ static constexpr char const *
+ phaseIntermediateMinVolFractionString() { return "phaseIntermediateMinVolFraction"; }
+ //to decide wheter drainage/drainage to imbibition or imbibition/imbibition to drainage
+ };
+
+
+private:
+ virtual void postProcessInput();
+
+ virtual void initializePreSubGroups() override;
+
+ void resizeFields( localIndex const size,
+ localIndex const numPts ) override;
+
+
+ /**
+ * @brief Create all the table kernel wrappers needed for the simulation (for all the phases present)
+ */
+ void createAllTableKernelWrappers();
+
+ /**
+ * @brief Compute the Land coefficient for the wetting and non-wetting phases
+ */
+ void computeLandCoefficient();
+
+ ///data members
+
+
+ //TODO impl
+// array1d< integer > m_tCurveOption;
+
+ KilloughHysteresis::HysteresisCurve m_wettingCurve;
+ KilloughHysteresis::HysteresisCurve m_nonWettingCurve;
+
+ ///tables
+ //2p
+ string m_drainageWettingNonWettingCapPresTableName;
+ string m_imbibitionWettingNonWettingCapPresTableName;
+ //3p
+ string m_drainageWettingIntermediateCapPresTableName;
+ string m_drainageNonWettingIntermediateCapPresTableName;
+ string m_imbibitionWettingIntermediateCapPresTableName;
+ string m_imbibitionNonWettingIntermediateCapPresTableName;
+ // kernel wrappers
+ /// Imbibition kernel wrappers for relative permeabilities in the following order:
+ /// 0- drainage
+ /// 1- imbibition (cf. struct ModeIndexType)
+ //2p
+ array1d< TableFunction::KernelWrapper > m_wettingNonWettingCapillaryPressureKernelWrappers;
+ array1d< TableFunction::KernelWrapper > m_inverseWettingNonWettingCapillaryPressureKernelWrappers;
+ //3p
+ array1d< TableFunction::KernelWrapper > m_wettingIntermediateCapillaryPressureKernelWrappers;
+ array1d< TableFunction::KernelWrapper > m_inverseWettingIntermediateCapillaryPressureKernelWrappers;
+ array1d< TableFunction::KernelWrapper > m_nonWettingIntermediateCapillaryPressureKernelWrappers;
+ array1d< TableFunction::KernelWrapper > m_inverseNonWettingIntermediateCapillaryPressureKernelWrappers;
+
+ // Store inverse tables to keep them alive
+ std::vector< std::shared_ptr< TableFunction > > m_inverseTables;
+
+
+ /// Flag to specify whether the phase has hysteresis or not (deduced from table input)
+ array1d< integer > m_phaseHasHysteresis;
+
+ /// Trapping parameter from the Land model (typically called C)
+ array1d< real64 > m_landParam;
+
+ /// Parameter a introduced by Jerauld in the Land model
+ real64 m_jerauldParam_a;
+
+ /// Parameter b introduced by Jerauld in the Land model
+ real64 m_jerauldParam_b;
+
+ /// Curvature parameter in Killough wetting phase hysteresis (Scanning curves curvatures)
+ real64 m_killoughCurvatureParamCapPres;
+
+ /// Cell-wise status imbibition, imbibitioon_to_drainage, ... etc
+ array1d< integer > m_mode;
+
+ // Max historical saturations
+ /// Minimum historical phase volume fraction for each phase
+ array2d< real64, compflow::LAYOUT_PHASE > m_phaseMinHistoricalVolFraction;
+
+ /// Maximum historical phase volume fraction for each phase
+ array2d< real64, compflow::LAYOUT_PHASE > m_phaseMaxHistoricalVolFraction;
+
+ /// Peak saturation reached during Mode 2 (DRAINAGE_TO_IMBIBITION) for each phase
+ array2d< real64, compflow::LAYOUT_PHASE > m_phaseMode2PeakVolFraction;
+
+ //needed in hysteresis of wetting phase
+ real64 m_phaseIntermediateMinVolFraction;
+
+};
+
+// Standard 3-argument compute method for compatibility with InverseCapillaryPressure
+// Uses zero/default values for historical fractions (no hysteresis in inverse computation)
+GEOS_HOST_DEVICE
+inline void TableCapillaryPressureHysteresis::KernelWrapper::compute(
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseCapPressure,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPressure_dPhaseVolFrac
+ ) const
+{
+ // Create temporary arrays for historical fractions and trapped fraction
+ // Initialize to zero/default values since inverse computation doesn't use hysteresis
+ constexpr integer MAX_NUM_PHASES = CapillaryPressureBase::MAX_NUM_PHASES;
+ real64 phaseMaxHistoricalVolFraction[MAX_NUM_PHASES]{};
+ real64 phaseMinHistoricalVolFraction[MAX_NUM_PHASES]{};
+ real64 phaseTrappedVolFrac[MAX_NUM_PHASES]{};
+ real64 phaseMode2PeakVolFraction[MAX_NUM_PHASES]{};
+ ModeIndexType mode = ModeIndexType::DRAINAGE; // Default to drainage mode
+
+ // Create ArrayView from stack arrays, then get slices
+ integer const numPhases = LvArray::integerConversion< integer >( phaseVolFraction.size() );
+ localIndex dims[1] = { numPhases };
+ localIndex strides[1] = { 1 };
+
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const phaseMaxHistSlice(
+ phaseMaxHistoricalVolFraction, dims, strides );
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const phaseMinHistSlice(
+ phaseMinHistoricalVolFraction, dims, strides );
+ arraySlice1d< real64, cappres::USD_CAPPRES - 2 > phaseTrappedSlice(
+ phaseTrappedVolFrac, dims, strides );
+ arraySlice1d< real64, compflow::USD_PHASE - 1 > phaseMode2PeakSlice(
+ phaseMode2PeakVolFraction, dims, strides );
+
+ // Call the full compute method
+ compute( phaseVolFraction,
+ phaseMaxHistSlice,
+ phaseMinHistSlice,
+ phaseTrappedSlice,
+ phaseCapPressure,
+ dPhaseCapPressure_dPhaseVolFrac,
+ mode,
+ phaseMode2PeakSlice );
+}
+
+GEOS_HOST_DEVICE
+inline void TableCapillaryPressureHysteresis::KernelWrapper::compute(
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMaxHistoricalVolFraction,
+ arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseMinHistoricalVolFraction,
+ arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseTrappedVolFrac,
+ arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseCapPressure,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPressure_dPhaseVolFrac,
+ ModeIndexType & mode,
+ arraySlice1d< real64, compflow::USD_PHASE - 1 > & phaseMode2PeakVolFraction
+ ) const
+{
+ // Early return if m_phaseOrder is empty or input arrays are empty
+ if( m_phaseOrder.size() == 0 ||
+ phaseVolFraction.size() == 0 ||
+ phaseCapPressure.size() == 0 )
+ {
+ return;
+ }
+
+ LvArray::forValuesInSlice( dPhaseCapPressure_dPhaseVolFrac, []( real64 & val ) { val = 0.0; } );
+
+ using PT = CapillaryPressureBase::PhaseType;
+ // Check bounds before accessing m_phaseOrder
+ integer const ipWater = ( PT::WATER < m_phaseOrder.size() ) ? m_phaseOrder[PT::WATER] : -1;
+ integer const ipOil = ( PT::OIL < m_phaseOrder.size() ) ? m_phaseOrder[PT::OIL] : -1;
+ integer const ipGas = ( PT::GAS < m_phaseOrder.size() ) ? m_phaseOrder[PT::GAS] : -1;
+
+ if( ipWater >= 0 && ipOil >= 0 && ipGas >= 0 )
+ {
+ computeThreePhase( ipWater, // wetting
+ ipOil, // intermediate
+ ipGas, // non-wetting
+ phaseVolFraction,
+ phaseMaxHistoricalVolFraction,
+ phaseMinHistoricalVolFraction,
+ phaseTrappedVolFrac,
+ phaseCapPressure,
+ dPhaseCapPressure_dPhaseVolFrac,
+ mode,
+ phaseMode2PeakVolFraction );
+
+ }
+ else if( ipWater < 0 )
+ {
+ computeTwoPhaseNonWetting( ipOil, // leading
+ ipGas, // deduced
+ phaseVolFraction,
+ phaseMaxHistoricalVolFraction,
+ phaseMinHistoricalVolFraction,
+ phaseTrappedVolFrac,
+ phaseCapPressure,
+ dPhaseCapPressure_dPhaseVolFrac,
+ mode );
+ }
+ else if( ipOil < 0 )
+ {
+ computeTwoPhaseWetting( ipWater, // leading
+ ipGas, // deduced
+ phaseVolFraction,
+ phaseMaxHistoricalVolFraction,
+ phaseMinHistoricalVolFraction,
+ phaseTrappedVolFrac,
+ phaseCapPressure,
+ dPhaseCapPressure_dPhaseVolFrac,
+ mode,
+ phaseMode2PeakVolFraction );
+ }
+ else if( ipGas < 0 )
+ {
+ computeTwoPhaseWetting( ipWater, //leading
+ ipOil, //deduced
+ phaseVolFraction,
+ phaseMaxHistoricalVolFraction,
+ phaseMinHistoricalVolFraction,
+ phaseTrappedVolFrac,
+ phaseCapPressure,
+ dPhaseCapPressure_dPhaseVolFrac,
+ mode,
+ phaseMode2PeakVolFraction );
+ }
+
+
+}
+
+GEOS_HOST_DEVICE
+inline void TableCapillaryPressureHysteresis::KernelWrapper::update( const geos::localIndex k,
+ const geos::localIndex q,
+ const arraySlice1d< const geos::real64,
+ compflow::USD_PHASE
+ - 1 > & phaseVolFraction ) const
+{
+ // Create a reference to the Mode 2 peak slice for this element
+ // m_phaseMode2PeakVolFraction uses compflow::LAYOUT_PHASE, so use compflow::USD_PHASE - 1
+ arraySlice1d< real64, compflow::USD_PHASE - 1 > phaseMode2PeakSlice = m_phaseMode2PeakVolFraction[k];
+ compute( phaseVolFraction,
+ m_phaseMaxHistoricalVolFraction[k],
+ m_phaseMinHistoricalVolFraction[k],
+ m_phaseTrappedVolFrac[k][q],
+ m_phaseCapPressure[k][q],
+ m_dPhaseCapPressure_dPhaseVolFrac[k][q],
+ m_mode[k],
+ phaseMode2PeakSlice );
+}
+
+
+} //constitutive
+} // geos
+
+#endif //GEOS_CONSTITUTIVE_TABLECAPILLARYPRESSUREHYSTERESIS_HPP
diff --git a/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.cpp b/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.cpp
index 74870cdb909..eb58fc8abea 100644
--- a/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.cpp
+++ b/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.cpp
@@ -123,6 +123,7 @@ VanGenuchtenCapillaryPressure::createKernelWrapper()
m_volFracScale,
m_phaseTypes,
m_phaseOrder,
+ m_phaseTrappedVolFrac,
m_phaseCapPressure,
m_dPhaseCapPressure_dPhaseVolFrac );
}
diff --git a/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.hpp b/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.hpp
index f3af8198d60..2234b405037 100644
--- a/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.hpp
+++ b/src/coreComponents/constitutive/capillaryPressure/VanGenuchtenCapillaryPressure.hpp
@@ -39,10 +39,12 @@ class VanGenuchtenCapillaryPressureUpdate final : public CapillaryPressureBaseUp
real64 const volFracScale,
arrayView1d< integer const > const & phaseTypes,
arrayView1d< integer const > const & phaseOrder,
+ arrayView3d< geos::real64, cappres::USD_CAPPRES > const & phaseTrapped,
arrayView3d< real64, cappres::USD_CAPPRES > const & phaseCapPressure,
arrayView4d< real64, cappres::USD_CAPPRES_DS > const & dPhaseCapPressure_dPhaseVolFrac )
: CapillaryPressureBaseUpdate( phaseTypes,
phaseOrder,
+ phaseTrapped,
phaseCapPressure,
dPhaseCapPressure_dPhaseVolFrac ),
m_phaseMinVolumeFraction( phaseMinVolumeFraction ),
@@ -57,6 +59,11 @@ class VanGenuchtenCapillaryPressureUpdate final : public CapillaryPressureBaseUp
arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const;
+ GEOS_HOST_DEVICE
+ void computeInv( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const;
+
GEOS_HOST_DEVICE
virtual void update( localIndex const k,
localIndex const q,
@@ -189,6 +196,69 @@ VanGenuchtenCapillaryPressureUpdate::
}
}
+GEOS_HOST_DEVICE
+inline void
+VanGenuchtenCapillaryPressureUpdate::
+ computeInv( arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFraction,
+ arraySlice1d< real64, cappres::USD_CAPPRES - 2 > const & phaseCapPres,
+ arraySlice2d< real64, cappres::USD_CAPPRES_DS - 2 > const & dPhaseCapPres_dPhaseVolFrac ) const
+{
+ LvArray::forValuesInSlice( dPhaseCapPres_dPhaseVolFrac, []( real64 & val ){ val = 0.0; } );
+
+ // the VanGenuchten model does not support volFracScaled = 0 and = 1
+ // hence we need an epsilon value to avoid a division by zero
+ // TODO: for S < epsilon and S > 1 - epsilon, replace the original unbounded VG curve with a bounded power-law
+ // extension
+ real64 const eps = m_capPressureEpsilon;
+ real64 const volFracScaleInv = 1.0 / m_volFracScale;
+
+ // compute first water-oil capillary pressure as a function of water-phase vol fraction
+ integer const ip_water = m_phaseOrder[CapillaryPressureBase::PhaseType::WATER];
+ if( ip_water >= 0 )
+ {
+
+ real64 const volFracScaled = (phaseVolFraction[ip_water] - m_phaseMinVolumeFraction[ip_water]) * volFracScaleInv;
+ real64 const exponentInv = m_phaseCapPressureExponentInv[ip_water]; // div by 0 taken care of by initialization
+ // check
+ real64 const multiplier = m_phaseCapPressureMultiplier[ip_water];
+
+ real64 const scaledWettingVolFrac = volFracScaled;
+ real64 const dScaledWettingPhaseVolFrac_dVolFrac = volFracScaleInv;
+
+ evaluateVanGenuchtenFunction( scaledWettingVolFrac,
+ dScaledWettingPhaseVolFrac_dVolFrac,
+ exponentInv,
+ multiplier,
+ eps,
+ phaseCapPres[ip_water],
+ dPhaseCapPres_dPhaseVolFrac[ip_water][ip_water] );
+
+ }
+
+
+ // then compute the oil-gas capillary pressure as a function of gas-phase vol fraction
+ integer const ip_gas = m_phaseOrder[CapillaryPressureBase::PhaseType::GAS];
+ if( ip_gas >= 0 )
+ {
+ real64 const volFracScaled = (phaseVolFraction[ip_gas] - m_phaseMinVolumeFraction[ip_gas]) * volFracScaleInv;
+ real64 const exponentInv = m_phaseCapPressureExponentInv[ip_gas]; // div by 0 taken care of by initialization
+ // check
+ real64 const multiplier = -m_phaseCapPressureMultiplier[ip_gas]; // for gas capillary pressure, take the opposite
+ // of the VG function
+
+ real64 const scaledWettingVolFrac = 1-volFracScaled;
+ real64 const dScaledWettingPhaseVolFrac_dVolFrac = -volFracScaleInv;
+
+ evaluateVanGenuchtenFunction( scaledWettingVolFrac,
+ dScaledWettingPhaseVolFrac_dVolFrac,
+ exponentInv,
+ multiplier,
+ eps,
+ phaseCapPres[ip_gas],
+ dPhaseCapPres_dPhaseVolFrac[ip_gas][ip_gas] );
+ }
+}
+
GEOS_HOST_DEVICE
GEOS_FORCE_INLINE
void
diff --git a/src/coreComponents/constitutive/docs/TwoPhaseFluid.rst b/src/coreComponents/constitutive/docs/TwoPhaseFluid.rst
new file mode 100644
index 00000000000..39b35510c63
--- /dev/null
+++ b/src/coreComponents/constitutive/docs/TwoPhaseFluid.rst
@@ -0,0 +1,90 @@
+.. _TwoPhaseFluid:
+
+############################################
+Two-phase fluid model
+############################################
+
+Overview
+=========================
+
+This model represents a two-phase fluid with pressure-dependent density and viscosity.
+
+For each phase, both density and viscosity are described as tabulated data, either in the form of ``TableFunction`` or text files.
+
+In the case of text files, one file is expected per phase and should consist of three columns: pressure, density and viscosity.
+
+Note that currently, there is no temperature dependence in the model.
+
+
+Parameters
+=========================
+
+The model is represented by ```` node in the input.
+
+The following attributes are supported:
+
+.. include:: /docs/sphinx/datastructure/TwoPhaseFluid.rst
+
+
+Example using TableFunctions
+============================
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Example using text files
+=========================
+
+.. code-block:: xml
+
+
+
+
+
+
+with, for example, ``water.txt`` being set as:
+
+.. code-block:: text
+
+ # P(Pa) Dens(kg/m3) Visc(Pa.s)
+ 2068000 980.683 0.0003
+ 5516000 982.07 0.0003
+ 30600000 992.233 0.0003
+ 55160000 1002.265 0.0003
diff --git a/src/coreComponents/constitutive/fluid/twophasefluid/TwoPhaseFluid.cpp b/src/coreComponents/constitutive/fluid/twophasefluid/TwoPhaseFluid.cpp
new file mode 100644
index 00000000000..ad6379ea129
--- /dev/null
+++ b/src/coreComponents/constitutive/fluid/twophasefluid/TwoPhaseFluid.cpp
@@ -0,0 +1,268 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 Total, S.A
+ * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
+ * Copyright (c) 2023-2024 Chevron
+ * Copyright (c) 2019- GEOS/GEOSX Contributors
+ * All rights reserved
+ *
+ * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+
+/**
+ * @file TwoPhaseFluid.cpp
+ */
+
+#include "constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp" // for readTable
+#include "TwoPhaseFluid.hpp"
+#include "TwoPhaseFluidFields.hpp"
+
+#include "functions/FunctionManager.hpp"
+
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+namespace constitutive
+{
+
+
+TwoPhaseFluid::TwoPhaseFluid( string const & name, Group * const parent )
+ : ConstitutiveBase( name, parent )
+{
+ registerWrapper( viewKeyStruct::phaseNamesString(), &m_phaseNames ).
+ setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "List of fluid phases" );
+
+ // 1) First option: specify PVT tables from one file per phase, read the files line by line, and populate the internal TableFunctions
+ registerWrapper( viewKeyStruct::tableFilesString(), &m_tableFiles ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setRestartFlags( RestartFlags::NO_WRITE ).
+ setDescription( "List of filenames with input PVT tables (one per phase)" );
+
+ // 2) Second option: specify TableFunction names for each phase,
+ registerWrapper( viewKeyStruct::densityTableNamesString(), &m_densityTableNames ).
+ setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "List of density TableFuncion names from the Function block. \n"
+ "The user must provide one TableFunction per phase, respecting the order provided in \"phaseNames\"." );
+
+ registerWrapper( viewKeyStruct::viscosityTableNamesString(), &m_viscosityTableNames ).
+ setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "List of viscosity TableFuncion names from the Function block. \n"
+ "The user must provide one TableFunction per phase, respecting the order provided in \"phaseNames\"." );
+
+ registerField( fields::twophasefluid::phaseDensity{}, &m_phaseDensity.value );
+ registerField( fields::twophasefluid::dPhaseDensity{}, &m_phaseDensity.derivs );
+ registerField( fields::twophasefluid::phaseDensity_n{}, &m_phaseDensity_n );
+
+ registerField( fields::twophasefluid::phaseViscosity{}, &m_phaseViscosity.value );
+ registerField( fields::twophasefluid::dPhaseViscosity{}, &m_phaseViscosity.derivs );
+}
+
+
+std::unique_ptr< ConstitutiveBase >
+TwoPhaseFluid::deliverClone( string const & name, Group * const parent ) const
+{
+ return ConstitutiveBase::deliverClone( name, parent );
+}
+
+
+void TwoPhaseFluid::resizeFields( localIndex const size, localIndex const numPts )
+{
+ // Assume sole dependency on pressure, i.e. one derivative
+ m_phaseDensity.value.resize( size, numPts, 2 );
+ m_phaseDensity.derivs.resize( size, numPts, 2, 1 );
+
+ m_phaseDensity_n.resize( size, numPts, 2 );
+
+ m_phaseViscosity.value.resize( size, numPts, 2 );
+ m_phaseViscosity.derivs.resize( size, numPts, 2, 1 );
+}
+
+
+void TwoPhaseFluid::allocateConstitutiveData( dataRepository::Group & parent,
+ localIndex const numConstitutivePointsPerParentIndex )
+{
+ ConstitutiveBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex );
+ resizeFields( parent.size(), numConstitutivePointsPerParentIndex );
+}
+
+
+void TwoPhaseFluid::postInputInitialization()
+{
+ ConstitutiveBase::postInputInitialization();
+
+ // Input relationships can be provided either as text files or TableFunctions.
+ m_tableFiles.empty() ? readInputDataFromTableFunctions() : readInputDataFromFileTableFunctions();
+
+ checkTableConsistency();
+}
+
+
+void TwoPhaseFluid::fillData( integer const ip,
+ array1d< array1d< real64 > > const & tableValues )
+{
+ array1d< array1d< real64 > > pressureCoords( 1 );
+ pressureCoords[0].resize( tableValues.size() );
+ array1d< real64 > density( tableValues.size() );
+ array1d< real64 > viscosity( tableValues.size() );
+
+ for( localIndex i = 0; i < tableValues.size(); ++i )
+ {
+ GEOS_THROW_IF_NE_MSG( tableValues[i].size(), 3,
+ GEOS_FMT( "{}: three columns (pressure, density, and viscosity) are expected", getFullName() ),
+ InputError );
+
+ pressureCoords[0][i] = tableValues[i][0];
+ density[i] = tableValues[i][1];
+ viscosity[i] = tableValues[i][2];
+ }
+
+ string const densityTableName = getName() + "DensityPhase" + GEOS_FMT( "{}", ip );
+ string const viscosityTableName = getName() + "ViscosityPhase" + GEOS_FMT( "{}", ip );
+ m_densityTableNames.emplace_back( densityTableName );
+ m_viscosityTableNames.emplace_back( viscosityTableName );
+
+ FunctionManager & functionManager = FunctionManager::getInstance();
+
+ TableFunction & tableDensity =
+ dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", densityTableName ) );
+ tableDensity.setTableCoordinates( pressureCoords, { units::Pressure } );
+ tableDensity.setTableValues( density, units::Density );
+ tableDensity.setInterpolationMethod( TableFunction::InterpolationType::Linear );
+
+ TableFunction & tableViscosity =
+ dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", viscosityTableName ) );
+ tableViscosity.setTableCoordinates( pressureCoords, { units::Pressure } );
+ tableViscosity.setTableValues( viscosity, units::Viscosity );
+ tableViscosity.setInterpolationMethod( TableFunction::InterpolationType::Linear );
+}
+
+
+void TwoPhaseFluid::readInputDataFromFileTableFunctions()
+{
+ // Check for ambiguous definition
+ GEOS_THROW_IF( !(m_densityTableNames.empty() && m_viscosityTableNames.empty()),
+ GEOS_FMT( "{}: input is redundant (both TableFunction names and text files)", getFullName() ),
+ InputError );
+
+
+ // Check that we have exactly two table files (one per phase)
+ GEOS_THROW_IF_NE_MSG( m_tableFiles.size(), 2,
+ GEOS_FMT( "{}: expecting two table files (one per phase)", getFullName() ),
+ InputError );
+
+ array1d< array1d< real64 > > tableValues;
+ for( integer ip = 0; ip < 2; ++ip )
+ {
+ tableValues.clear();
+ geos::constitutive::PVTProps::BlackOilTables::readTable( m_tableFiles[ip], 3, tableValues );
+ fillData( ip, tableValues );
+ }
+}
+
+
+void TwoPhaseFluid::readInputDataFromTableFunctions()
+{
+ // Check for ambiguous definition
+ GEOS_THROW_IF( !m_tableFiles.empty(),
+ GEOS_FMT( "{}: input is redundant (both TableFunction names and text files)", getFullName() ),
+ InputError );
+
+ // Since we are considering a two phase fluid, we should have exactly 2 tables per property
+ GEOS_THROW_IF_NE_MSG( m_densityTableNames.size(), 2,
+ GEOS_FMT( "{}: one density table must be provided for each phase", getFullName() ),
+ InputError );
+
+ GEOS_THROW_IF_NE_MSG( m_viscosityTableNames.size(), 2,
+ GEOS_FMT( "{}: one viscosity table must be provided for each phase", getFullName() ),
+ InputError );
+
+
+ FunctionManager const & functionManager = FunctionManager::getInstance();
+
+ for( integer iph = 0; iph < 2; ++iph )
+ {
+ GEOS_THROW_IF( !functionManager.hasGroup( m_densityTableNames[iph] ),
+ GEOS_FMT( "{}: density table '{}' not found", getFullName(), m_densityTableNames[iph] ),
+ InputError );
+
+ GEOS_THROW_IF( !functionManager.hasGroup( m_viscosityTableNames[iph] ),
+ GEOS_FMT( "{}: viscosity table '{}' not found", getFullName(), m_viscosityTableNames[iph] ),
+ InputError );
+ }
+}
+
+
+void TwoPhaseFluid::initializePostSubGroups()
+{
+ ConstitutiveBase::initializePostSubGroups();
+
+ FunctionManager const & functionManager = FunctionManager::getInstance();
+ for( integer iph = 0; iph < 2; ++iph )
+ {
+ // Grab the tables by name from the function manager,
+ // then add them in a list to create their table wrappers when needed
+ TableFunction const & densityTable = functionManager.getGroup< TableFunction const >( m_densityTableNames[iph] );
+ m_densityTables.emplace_back( &densityTable );
+ m_densityTableKernels.emplace_back( m_densityTables[iph]->createKernelWrapper() );
+
+ TableFunction const & viscosityTable = functionManager.getGroup< TableFunction const >( m_viscosityTableNames[iph] );
+ m_viscosityTables.emplace_back( &viscosityTable );
+ m_viscosityTableKernels.emplace_back( m_viscosityTables[iph]->createKernelWrapper() );
+ }
+}
+
+
+void TwoPhaseFluid::checkTableConsistency() const
+{
+ FunctionManager const & functionManager = FunctionManager::getInstance();
+ for( integer iph = 0; iph < 2; ++iph )
+ {
+ TableFunction const & densityTable = functionManager.getGroup< TableFunction const >( m_densityTableNames[iph] );
+ arrayView1d< real64 const > const density = densityTable.getValues();
+
+ for( localIndex i = 1; i < density.size(); ++i )
+ {
+ GEOS_THROW_IF( density[i] - density[i-1] < 0,
+ GEOS_FMT( "{}: in table '{}' density values must be increasing", getFullName(), densityTable.getName() ),
+ InputError );
+ }
+ }
+}
+
+
+TwoPhaseFluid::KernelWrapper
+TwoPhaseFluid::createKernelWrapper()
+{
+ return KernelWrapper( m_densityTableKernels,
+ m_viscosityTableKernels,
+ m_phaseDensity.toView(),
+ m_phaseViscosity.toView());
+}
+
+
+TwoPhaseFluid::KernelWrapper::KernelWrapper(
+ arrayView1d< TableFunction::KernelWrapper const > densityTables,
+ arrayView1d< TableFunction::KernelWrapper const > viscosityTables,
+ PhaseProp::ViewType phaseDensity,
+ PhaseProp::ViewType phaseViscosity )
+ : m_densityTables( std::move( densityTables )),
+ m_viscosityTables( std::move( viscosityTables )),
+ m_phaseDensity( std::move( phaseDensity )),
+ m_phaseViscosity( std::move( phaseViscosity )) {}
+
+
+REGISTER_CATALOG_ENTRY( ConstitutiveBase, TwoPhaseFluid, string const &, Group * const )
+
+} // namespace constitutive
+} // namespace geos
diff --git a/src/coreComponents/constitutive/fluid/twophasefluid/TwoPhaseFluid.hpp b/src/coreComponents/constitutive/fluid/twophasefluid/TwoPhaseFluid.hpp
new file mode 100644
index 00000000000..18cdc357bb0
--- /dev/null
+++ b/src/coreComponents/constitutive/fluid/twophasefluid/TwoPhaseFluid.hpp
@@ -0,0 +1,344 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 Total, S.A
+ * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
+ * Copyright (c) 2023-2024 Chevron
+ * Copyright (c) 2019- GEOS/GEOSX Contributors
+ * All rights reserved
+ *
+ * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+
+/**
+ * @file TwoPhaseFluid.hpp
+ */
+
+#ifndef GEOS_CONSTITUTIVE_FLUID_TWOPHASEFLUID_TWOPHASEFLUID_HPP_
+#define GEOS_CONSTITUTIVE_FLUID_TWOPHASEFLUID_TWOPHASEFLUID_HPP_
+
+#include "common/DataLayouts.hpp"
+#include "functions/TableFunction.hpp"
+#include "constitutive/ConstitutiveBase.hpp"
+
+#include "constitutive/fluid/multifluid/Layouts.hpp"
+#include "constitutive/fluid/multifluid/MultiFluidUtils.hpp"
+
+#include "constitutive/ConstitutivePassThruHandler.hpp"
+
+
+namespace geos
+{
+namespace constitutive
+{
+
+class TwoPhaseFluid : public ConstitutiveBase
+{
+public:
+
+ TwoPhaseFluid( string const & name,
+ Group * const parent );
+
+ virtual std::unique_ptr< ConstitutiveBase >
+ deliverClone( string const & name,
+ Group * const parent ) const override;
+
+ virtual void allocateConstitutiveData( dataRepository::Group & parent,
+ localIndex const numConstitutivePointsPerParentIndex ) override;
+
+ /**
+ * @name Static Factory Catalog members and functions
+ */
+ ///@{
+
+ /**
+ * @brief Static catalog string
+ * @return A string that is used to register/lookup this class in the registry
+ */
+ static std::string catalogName() { return "TwoPhaseFluid"; }
+
+ /**
+ * @brief Get catalog name
+ * @return Name string
+ */
+ virtual string getCatalogName() const override { return catalogName(); }
+
+ ///@}
+
+
+
+ /**
+ * @brief Getter for the fluid phase names
+ * @return an array storing the phase names
+ */
+ string_array const & phaseNames() const { return m_phaseNames; }
+
+ struct viewKeyStruct : ConstitutiveBase::viewKeyStruct
+ {
+ static constexpr char const * tableFilesString() { return "tableFiles"; }
+ static constexpr char const * phaseNamesString() { return "phaseNames"; }
+ static constexpr char const * densityTableNamesString() { return "densityTableNames"; }
+ static constexpr char const * viscosityTableNamesString() { return "viscosityTableNames"; }
+ };
+
+ arrayView3d< real64 const, multifluid::USD_PHASE > phaseDensity_n() const
+ { return m_phaseDensity_n; }
+
+ arrayView3d< real64 const, multifluid::USD_PHASE > phaseDensity() const
+ { return m_phaseDensity.value; }
+
+ arrayView4d< real64 const, multifluid::USD_PHASE_DC > dPhaseDensity() const
+ { return m_phaseDensity.derivs; }
+
+ arrayView3d< real64 const, multifluid::USD_PHASE > phaseViscosity() const
+ { return m_phaseViscosity.value; }
+
+ arrayView4d< real64 const, multifluid::USD_PHASE_DC > dPhaseViscosity() const
+ { return m_phaseViscosity.derivs; }
+
+ using PhaseProp = MultiFluidVar< real64, 3, constitutive::multifluid::LAYOUT_PHASE, constitutive::multifluid::LAYOUT_PHASE_DC >;
+
+
+ class KernelWrapper
+ {
+public:
+
+ /// @cond DO_NOT_DOCUMENT
+ /// We need these SMFs to avoid host-device errors with CUDA.
+ KernelWrapper() = default;
+ KernelWrapper( KernelWrapper const & ) = default;
+ KernelWrapper & operator=( KernelWrapper const & ) = default;
+ KernelWrapper & operator=( KernelWrapper && ) = default;
+ /// @endcond
+
+ /**
+ * @brief Get number of elements in this wrapper.
+ * @return number of elements
+ */
+ GEOS_HOST_DEVICE
+ GEOS_FORCE_INLINE
+ localIndex numElems() const { return m_phaseDensity.value.size( 0 ); }
+
+ /**
+ * @brief Get number of gauss points per element.
+ * @return number of gauss points per element
+ */
+ GEOS_HOST_DEVICE
+ GEOS_FORCE_INLINE
+ localIndex numGauss() const { return m_phaseDensity.value.size( 1 ); }
+
+
+ GEOS_HOST_DEVICE
+ void compute( real64 const pressure,
+ PhaseProp::SliceType const phaseDensity,
+ PhaseProp::SliceType const phaseViscosity ) const;
+
+ GEOS_HOST_DEVICE
+ void update( localIndex const k,
+ localIndex const q,
+ real64 const pressure ) const;
+
+private:
+
+ friend class TwoPhaseFluid;
+
+ /**
+ * @brief Constructor for the class doing in-kernel two-phase fluid updates
+ * @param[in] densityTables density tables
+ * @param[in] viscosityTables viscosity tables
+ * @param[in] phaseDensity phase densities (+ derivatives) in the cell
+ * @param[in] phaseViscosity phase viscosities (+ derivatives) in the cell
+ */
+ KernelWrapper(
+ arrayView1d< TableFunction::KernelWrapper const > densityTables,
+ arrayView1d< TableFunction::KernelWrapper const > viscosityTables,
+ PhaseProp::ViewType phaseDensity,
+ PhaseProp::ViewType phaseViscosity );
+
+
+protected:
+
+ KernelWrapper(
+ arrayView1d< TableFunction::KernelWrapper const > densityTables,
+ arrayView1d< TableFunction::KernelWrapper const > viscosityTables
+ );
+
+ /// Table kernel wrappers to interpolate in the two phase (\rho vs p) tables
+ arrayView1d< TableFunction::KernelWrapper const > m_densityTables;
+
+ /// Table kernel wrappers to interpolate in the two phase (\mu vs p) tables
+ arrayView1d< TableFunction::KernelWrapper const > m_viscosityTables;
+
+ /**
+ * @brief Utility function to compute densities as a function of pressure (keeping derivatives)
+ * @param[in] pressure pressure in the cell
+ * @param[out] phaseDensity the phase density in the cell (+ derivatives)
+ */
+ GEOS_HOST_DEVICE
+ void computeDensities( real64 const pressure,
+ PhaseProp::SliceType const & phaseDensity ) const;
+
+ /**
+ * @brief Utility function to compute viscosities as a function of pressure (keeping derivatives)
+ * @param[in] pressure pressure in the cell
+ * @param[out] phaseViscosity the phase viscosities in the cell (+ derivatives)
+ */
+ GEOS_HOST_DEVICE
+ void computeViscosities( real64 const pressure,
+ PhaseProp::SliceType const & phaseViscosity ) const;
+
+ /// Views on the phase properties
+ PhaseProp::ViewType m_phaseDensity;
+ PhaseProp::ViewType m_phaseViscosity;
+
+ }; //class KernelWrapper
+
+
+ string_array m_phaseNames;
+
+
+ path_array m_tableFiles;
+
+ /// Names of the density tables (one per phase)
+ string_array m_densityTableNames;
+
+ /// Names of the viscosity tables (one per phase)
+ string_array m_viscosityTableNames;
+
+ PhaseProp m_phaseDensity;
+ PhaseProp m_phaseViscosity;
+
+ /// Backup data
+ array3d< real64, multifluid::LAYOUT_PHASE > m_phaseDensity_n;
+
+
+ virtual void resizeFields( localIndex const size, localIndex const numPts );
+
+ virtual void postInputInitialization() override;
+
+ virtual void initializePostSubGroups() override;
+
+ /// Table kernel wrappers to interpolate (\rho vs p) tables
+ array1d< TableFunction const * > m_densityTables;
+ /// Table kernel wrappers of m_densityTables
+ array1d< TableFunction::KernelWrapper > m_densityTableKernels;
+
+ /// Table kernel wrappers to interpolate (\mu vs p) tables
+ array1d< TableFunction const * > m_viscosityTables;
+ /// Table kernel wrappers of m_viscosityTables
+ array1d< TableFunction::KernelWrapper > m_viscosityTableKernels;
+
+ KernelWrapper createKernelWrapper();
+
+
+private:
+ void readInputDataFromTableFunctions();
+ void readInputDataFromFileTableFunctions();
+
+ /**
+ * @brief Fill the fluid data (pressure, density, viscosity)
+ * @param[in] ip the index of the phase
+ * @param[in] tableValues the values in the fluid table
+ */
+ void fillData( integer const ip,
+ array1d< array1d< real64 > > const & tableValues );
+
+ /**
+ * @brief Check the monotonicity of the PVT relationship
+ */
+ void checkTableConsistency() const;
+};
+
+
+GEOS_HOST_DEVICE
+GEOS_FORCE_INLINE
+void TwoPhaseFluid::KernelWrapper::
+ computeDensities( real64 const pressure,
+ PhaseProp::SliceType const & phaseDensity ) const
+{
+ using Deriv = constitutive::multifluid::DerivativeOffset;
+
+ LvArray::forValuesInSlice( phaseDensity.derivs, []( real64 & val ) { val = 0.0; } );
+
+ for( integer iph = 0; iph < 2; ++iph )
+ {
+ // interpolate in the table to get the phase density and derivatives
+ real64 dPhaseDens_dPres = 0.0;
+
+ phaseDensity.value[iph] = m_densityTables[iph].compute( &pressure, &dPhaseDens_dPres );
+ phaseDensity.derivs[iph][Deriv::dP] = dPhaseDens_dPres;
+ }
+}
+
+
+GEOS_HOST_DEVICE
+GEOS_FORCE_INLINE
+void TwoPhaseFluid::KernelWrapper::
+ computeViscosities( real64 const pressure,
+ PhaseProp::SliceType const & phaseViscosity ) const
+{
+ using Deriv = constitutive::multifluid::DerivativeOffset;
+
+ LvArray::forValuesInSlice( phaseViscosity.derivs, []( real64 & val ) { val = 0.0; } );
+
+ for( integer iph = 0; iph < 2; ++iph )
+ {
+ // interpolate in the table to get the phase viscosity and derivatives
+ real64 dPhaseVisc_dPres = 0.0;
+ phaseViscosity.value[iph] = m_viscosityTables[iph].compute( &pressure, &dPhaseVisc_dPres );
+ phaseViscosity.derivs[iph][Deriv::dP] = dPhaseVisc_dPres;
+ }
+}
+
+
+GEOS_HOST_DEVICE
+GEOS_FORCE_INLINE
+void TwoPhaseFluid::KernelWrapper::
+ compute( real64 const pressure,
+ PhaseProp::SliceType const phaseDensity,
+ PhaseProp::SliceType const phaseViscosity ) const
+{
+ computeDensities( pressure,
+ phaseDensity );
+
+ computeViscosities( pressure,
+ phaseViscosity );
+}
+
+
+GEOS_HOST_DEVICE
+GEOS_FORCE_INLINE
+void TwoPhaseFluid::KernelWrapper::
+ update( localIndex const k,
+ localIndex const q,
+ real64 const pressure
+ ) const
+{
+ compute( pressure,
+ m_phaseDensity( k, q ),
+ m_phaseViscosity( k, q ) );
+}
+
+
+template< typename LAMBDA >
+void constitutiveUpdatePassThru( TwoPhaseFluid const & fluid,
+ LAMBDA && lambda )
+{
+ ConstitutivePassThruHandler< TwoPhaseFluid >::execute( fluid, std::forward< LAMBDA >( lambda ) );
+}
+
+
+template< typename LAMBDA >
+void constitutiveUpdatePassThru( TwoPhaseFluid & fluid,
+ LAMBDA && lambda )
+{
+ ConstitutivePassThruHandler< TwoPhaseFluid >::execute( fluid, std::forward< LAMBDA >( lambda ) );
+}
+
+} // namespace constitutive
+} // namespace geos
+
+#endif // GEOS_CONSTITUTIVE_FLUID_TWOPHASEFLUID_TWOPHASEFLUID_HPP_
diff --git a/src/coreComponents/constitutive/fluid/twophasefluid/TwoPhaseFluidFields.hpp b/src/coreComponents/constitutive/fluid/twophasefluid/TwoPhaseFluidFields.hpp
new file mode 100644
index 00000000000..9ce0dc5c33d
--- /dev/null
+++ b/src/coreComponents/constitutive/fluid/twophasefluid/TwoPhaseFluidFields.hpp
@@ -0,0 +1,84 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 Total, S.A
+ * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
+ * Copyright (c) 2023-2024 Chevron
+ * Copyright (c) 2019- GEOS/GEOSX Contributors
+ * All rights reserved
+ *
+ * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+
+/**
+ * @file TwoPhaseFluidFields.hpp
+ */
+
+#ifndef GEOS_CONSTITUTIVE_FLUID_TWOPHASEFLUIDFIELDS_HPP_
+#define GEOS_CONSTITUTIVE_FLUID_TWOPHASEFLUIDFIELDS_HPP_
+
+#include "constitutive/fluid/multifluid/Layouts.hpp"
+#include "mesh/MeshFields.hpp"
+
+
+namespace geos
+{
+
+namespace fields
+{
+
+namespace twophasefluid
+{
+
+using array3dLayoutPhase = array3d< real64, constitutive::multifluid::LAYOUT_PHASE >;
+using array4dLayoutPhase_d = array4d< real64, constitutive::multifluid::LAYOUT_PHASE_DC >;
+
+DECLARE_FIELD( phaseDensity,
+ "phaseDensity",
+ array3dLayoutPhase,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Phase density" );
+
+DECLARE_FIELD( phaseDensity_n,
+ "phaseDensity_n",
+ array3dLayoutPhase,
+ 0,
+ NOPLOT,
+ WRITE_AND_READ,
+ "Phase density at the previous converged time step" );
+
+DECLARE_FIELD( dPhaseDensity,
+ "dPhaseDensity",
+ array4dLayoutPhase_d,
+ 0,
+ NOPLOT,
+ NO_WRITE,
+ "Derivative of phase density with respect to pressure" );
+
+DECLARE_FIELD( phaseViscosity,
+ "phaseViscosity",
+ array3dLayoutPhase,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Phase viscosity" );
+
+DECLARE_FIELD( dPhaseViscosity,
+ "dPhaseViscosity",
+ array4dLayoutPhase_d,
+ 0,
+ NOPLOT,
+ NO_WRITE,
+ "Derivative of phase viscosity with respect to pressure" );
+
+} // namespace twophasefluid
+
+} // namespace constitutive
+} // namespace geos
+
+#endif // GEOS_CONSTITUTIVE_FLUID_TWOPHASEFLUIDFIELDS_HPP_
diff --git a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.hpp
index 476def9f455..21fdbe4a8a6 100644
--- a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.hpp
+++ b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyBakerRelativePermeability.hpp
@@ -139,19 +139,17 @@ class BrooksCoreyBakerRelativePermeability : public RelativePermeabilityBase
static constexpr char const * volFracScaleString() { return "volFracScale"; }
};
- arrayView1d< real64 const > getPhaseMinVolumeFraction() const override { return m_phaseMinVolumeFraction; };
-
real64 getWettingPhaseMinVolumeFraction() const override
{
integer ipWetting;
- std::tie( ipWetting, std::ignore ) = wettingAndNonWettingPhaseIndices();
+ std::tie( ipWetting, std::ignore ) = phaseIndex( getPhaseOrder());
return m_phaseMinVolumeFraction[ipWetting];
}
real64 getNonWettingMinVolumeFraction() const override
{
integer ipNonWetting;
- std::tie( std::ignore, ipNonWetting ) = wettingAndNonWettingPhaseIndices();
+ std::tie( std::ignore, ipNonWetting ) = phaseIndex( getPhaseOrder());
return m_phaseMinVolumeFraction[ipNonWetting];
};
diff --git a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.hpp
index 30ee2ff3692..2de3998a78e 100644
--- a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.hpp
+++ b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyRelativePermeability.hpp
@@ -105,19 +105,18 @@ class BrooksCoreyRelativePermeability : public RelativePermeabilityBase
static constexpr char const * volFracScaleString() { return "volFracScale"; }
};
//END_SPHINX_INCLUDE_01
- arrayView1d< real64 const > getPhaseMinVolumeFraction() const override { return m_phaseMinVolumeFraction; };
real64 getWettingPhaseMinVolumeFraction() const override
{
integer ipWetting;
- std::tie( ipWetting, std::ignore ) = wettingAndNonWettingPhaseIndices();
+ std::tie( ipWetting, std::ignore ) = phaseIndex( getPhaseOrder());
return m_phaseMinVolumeFraction[ipWetting];
}
real64 getNonWettingMinVolumeFraction() const override
{
integer ipNonWetting;
- std::tie( std::ignore, ipNonWetting ) = wettingAndNonWettingPhaseIndices();
+ std::tie( std::ignore, ipNonWetting ) = phaseIndex( getPhaseOrder());
return m_phaseMinVolumeFraction[ipNonWetting];
};
diff --git a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.hpp
index 47eefdd512a..2d83dcda597 100644
--- a/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.hpp
+++ b/src/coreComponents/constitutive/relativePermeability/BrooksCoreyStone2RelativePermeability.hpp
@@ -138,7 +138,7 @@ class BrooksCoreyStone2RelativePermeability : public RelativePermeabilityBase
static constexpr char const * volFracScaleString() { return "volFracScale"; }
};
- arrayView1d< real64 const > getPhaseMinVolumeFraction() const override { return m_phaseMinVolumeFraction; };
+ arrayView1d< real64 const > getPhaseMinVolumeFraction() const { return m_phaseMinVolumeFraction; };
real64 getWettingPhaseMinVolumeFraction() const override
{
diff --git a/src/coreComponents/constitutive/relativePermeability/KilloughHysteresis.hpp b/src/coreComponents/constitutive/relativePermeability/KilloughHysteresis.hpp
index 58499b94b64..48d2d3deaa2 100644
--- a/src/coreComponents/constitutive/relativePermeability/KilloughHysteresis.hpp
+++ b/src/coreComponents/constitutive/relativePermeability/KilloughHysteresis.hpp
@@ -137,18 +137,8 @@ class KilloughHysteresis
m_extremumPhaseVolFraction ),
InputError );
- GEOS_THROW_IF( m_criticalImbibitionValue < 0 || m_criticalImbibitionValue > 1,
- GEOS_FMT( "KilloughHysteresis: the critical imbibition relative permeability is equal to {} but must be between 0 an 1",
- m_criticalImbibitionValue ),
- InputError );
- GEOS_THROW_IF( m_criticalDrainageValue < 0 || m_criticalDrainageValue > 1,
- GEOS_FMT( "KilloughHysteresis: the critical drainage relative permeability is equal to {} but must be between 0 an 1",
- m_criticalDrainageValue ),
- InputError );
- GEOS_THROW_IF( m_extremumValue < 0 || m_extremumValue > 1,
- GEOS_FMT( "KilloughHysteresis: the extremum relative permeability is equal to {} but must be between 0 an 1",
- m_extremumValue ),
- InputError );
+ // Note: value validation removed because this struct is used for both relative permeability (0-1 range)
+ // and capillary pressure (can be in Pa or other units, typically >> 1). The value range depends on the application.
m_isWetting = m_criticalDrainagePhaseVolFraction > m_extremumPhaseVolFraction;
diff --git a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.cpp b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.cpp
index b947d6962bc..defeb65e19e 100644
--- a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.cpp
+++ b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.cpp
@@ -153,6 +153,7 @@ std::tuple< integer, integer > RelativePermeabilityBase::wettingAndNonWettingPha
return std::make_tuple( ipWetting, ipNonWetting );
}
+
} // namespace constitutive
} // namespace geos
diff --git a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.hpp b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.hpp
index 0bc67b26a39..0600a41643a 100644
--- a/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.hpp
+++ b/src/coreComponents/constitutive/relativePermeability/RelativePermeabilityBase.hpp
@@ -165,8 +165,8 @@ class RelativePermeabilityBase : public ConstitutiveBase
static std::tuple< integer, integer > phaseIndex( arrayView1d< integer const > const & phaseOrder );
arrayView1d< integer const > getPhaseOrder() const { return m_phaseOrder; }
- virtual arrayView1d< real64 const > getPhaseMinVolumeFraction() const = 0;
virtual real64 getWettingPhaseMinVolumeFraction() const = 0;
+
virtual real64 getNonWettingMinVolumeFraction() const = 0;
std::tuple< integer, integer > wettingAndNonWettingPhaseIndices() const;
@@ -217,6 +217,45 @@ class RelativePermeabilityBase : public ConstitutiveBase
};
+
+/// for use in RelpermDriver to browse the drainage curves
+/// by setting the MaxHistoricalNonWettingSat to Snwmin and MinWettingSat to Sw
+inline std::tuple< integer, integer > RelativePermeabilityBase::phaseIndex( arrayView1d< integer const > const & phaseOrder )
+{
+ using PT = PhaseType;
+ integer const ipWater = phaseOrder[PT::WATER];
+ integer const ipOil = phaseOrder[PT::OIL];
+ integer const ipGas = phaseOrder[PT::GAS];
+
+ integer ipWetting = -1, ipNonWetting = -1;
+
+ if( ipWater >= 0 && ipOil >= 0 && ipGas >= 0 )
+ {
+ ipWetting = ipWater;
+ ipNonWetting = ipGas;
+ }
+ else if( ipWater < 0 )
+ {
+ ipWetting = ipOil;
+ ipNonWetting = ipGas;
+ }
+ else if( ipOil < 0 )
+ {
+ ipWetting = ipWater;
+ ipNonWetting = ipGas;
+ }
+ else if( ipGas < 0 )
+ {
+ ipWetting = ipWater;
+ ipNonWetting = ipOil;
+ }
+
+ //maybe a bit too pythonic
+ return std::make_tuple( ipWetting, ipNonWetting );
+}
+
+
+
} // namespace constitutive
} // namespace geos
diff --git a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.hpp
index 7b2fb4d7bcd..255fa33aca3 100644
--- a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.hpp
+++ b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeability.hpp
@@ -142,19 +142,17 @@ class TableRelativePermeability : public RelativePermeabilityBase
static constexpr char const * threePhaseInterpolatorString() { return "threePhaseInterpolator"; }
};
- arrayView1d< real64 const > getPhaseMinVolumeFraction() const override { return m_phaseMinVolumeFraction; };
-
real64 getWettingPhaseMinVolumeFraction() const override
{
integer ipWetting;
- std::tie( ipWetting, std::ignore ) = wettingAndNonWettingPhaseIndices();
+ std::tie( ipWetting, std::ignore ) = phaseIndex( getPhaseOrder());
return m_phaseMinVolumeFraction[ipWetting];
}
real64 getNonWettingMinVolumeFraction() const override
{
integer ipNonWetting;
- std::tie( std::ignore, ipNonWetting ) = wettingAndNonWettingPhaseIndices();
+ std::tie( std::ignore, ipNonWetting ) = phaseIndex( getPhaseOrder());
return m_phaseMinVolumeFraction[ipNonWetting];
};
diff --git a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.cpp b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.cpp
index a93ab87c8a8..740ad7104e6 100644
--- a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.cpp
+++ b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHelpers.cpp
@@ -76,7 +76,7 @@ TableRelativePermeabilityHelpers::validateRelativePermeabilityTable( TableFuncti
if( isZero( relPerm[i-1] ) && !isZero( relPerm[i] ) )
{
phaseMinVolFrac = phaseVolFrac[i-1];
- phaseRelPermMinEndPoint = 0.;
+ phaseRelPermMinEndPoint = relPerm[i-1];
}
}
diff --git a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.cpp b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.cpp
index 7355dd8243d..8c38a09616e 100644
--- a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.cpp
+++ b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.cpp
@@ -22,7 +22,8 @@
#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp"
#include "constitutive/relativePermeability/TableRelativePermeabilityHelpers.hpp"
#include "functions/FunctionManager.hpp"
-#include "LogLevelsInfo.hpp"
+#include "constitutiveDrivers/relativePermeability/RelpermDriver.hpp"
+#include "constitutive/ConstitutiveManager.hpp"
namespace geos
{
@@ -89,48 +90,68 @@ TableRelativePermeabilityHysteresis::TableRelativePermeabilityHysteresis( std::s
"To neglect hysteresis on this phase, just use the same table name for the drainage and imbibition curves" );
// hysteresis input parameters
-
- registerWrapper( viewKeyStruct::landParameterString(), &m_landParam ).
- setInputFlag( InputFlags::FALSE ). // will be deduced from tables
+ registerWrapper( viewKeyStruct::phaseHasHysteresisString(), &m_phaseHasHysteresis ).
+ setInputFlag( InputFlags::FALSE )
+ . // will be deduced from tables
setSizedFromParent( 0 );
- // forwarded to KilloughHysteresis
- registerWrapper( KilloughHysteresis::viewKeyStruct::jerauldParameterAString(), &m_jerauldParam_a ).
- setInputFlag( InputFlags::OPTIONAL ).
- setApplyDefaultValue( 0.1 ).
- setDescription( "First parameter (modification parameter) introduced by Jerauld in the Land trapping model (see RTD documentation)." );
-
- registerWrapper( KilloughHysteresis::viewKeyStruct::jerauldParameterBString(), &m_jerauldParam_b ).
- setInputFlag( InputFlags::OPTIONAL ).
- setApplyDefaultValue( 0.0 ).
- setDescription( "Second parameter (modification parameter) introduced by Jerauld in the Land trapping model (see RTD documentation)." );
-
- registerWrapper( KilloughHysteresis::viewKeyStruct::killoughCurvatureParameterString(), &m_killoughCurvatureParamRelPerm ).
- setInputFlag( InputFlags::OPTIONAL ).
- setApplyDefaultValue( 1.0 ).
- setDescription( "Curvature parameter introduced by Killough for wetting-phase hysteresis (see RTD documentation)." );
+ registerField< fields::relperm::phaseMaxHistoricalVolFraction >(
+ &m_phaseMaxHistoricalVolFraction );
+ registerField< fields::relperm::phaseMinHistoricalVolFraction >(
+ &m_phaseMinHistoricalVolFraction );
- // structs
+ /// Killough data
registerWrapper( viewKeyStruct::drainageRelPermKernelWrappersString(),
&m_drainageRelPermKernelWrappers ).
setSizedFromParent( 0 ).
- setRestartFlags( RestartFlags::NO_WRITE );
+ setRestartFlags(
+ RestartFlags::NO_WRITE );
registerWrapper( viewKeyStruct::imbibitionRelPermKernelWrappersString(),
&m_imbibitionRelPermKernelWrappers ).
setSizedFromParent( 0 ).
- setRestartFlags( RestartFlags::NO_WRITE );
+ setRestartFlags(
+ RestartFlags::NO_WRITE );
- // Killough data
- registerWrapper( viewKeyStruct::wettingCurveString(), &m_wettingCurve ).
+ registerWrapper( viewKeyStruct::landParameterString(), &m_landParam ).
setInputFlag( InputFlags::FALSE ). // will be deduced from tables
- setSizedFromParent( 0 ).
- setRestartFlags( RestartFlags::NO_WRITE );
+ setSizedFromParent( 0 );
+
+
+ registerWrapper( viewKeyStruct::wettingCurveString(), &m_wettingCurve ).
+ setInputFlag(
+ InputFlags::FALSE ). // will be deduced from tables
+ setSizedFromParent(
+ 0 )
+ .setRestartFlags( RestartFlags::NO_WRITE );
registerWrapper( viewKeyStruct::nonWettingCurveString(), &m_nonWettingCurve ).
- setInputFlag( InputFlags::FALSE ). // will be deduced from tables
- setSizedFromParent( 0 ).
- setRestartFlags( RestartFlags::NO_WRITE );
+ setInputFlag(
+ InputFlags::FALSE ). // will be deduced from tables
+ setSizedFromParent(
+ 0 )
+ .setRestartFlags( RestartFlags::NO_WRITE );
+
+ //Forwarded to KilloughHysteresis
+ registerWrapper( KilloughHysteresis::viewKeyStruct::jerauldParameterAString(), &m_jerauldParam_a ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setApplyDefaultValue( 0.1 ).
+ setDescription(
+ "First parameter (modification parameter) introduced by Jerauld in the Land trapping model (see RTD documentation)." );
+
+ registerWrapper( KilloughHysteresis::viewKeyStruct::jerauldParameterBString(), &m_jerauldParam_b ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setApplyDefaultValue( 0.0 ).
+ setDescription(
+ "Second parameter (modification parameter) introduced by Jerauld in the Land trapping model (see RTD documentation)." );
+
+ registerWrapper( KilloughHysteresis::viewKeyStruct::killoughCurvatureParameterRelPermString(), &m_killoughCurvatureParamRelPerm ).
+ setInputFlag(
+ InputFlags::OPTIONAL ).
+ setApplyDefaultValue(
+ 1.0 ).
+ setDescription(
+ "Curvature parameter introduced by Killough for wetting-phase hysteresis (see RTD documentation)." );
registerWrapper( viewKeyStruct::waterOilMaxRelPermString(), &m_waterOilMaxRelPerm ).
setInputFlag( InputFlags::FALSE ). // will be deduced from tables
@@ -164,7 +185,6 @@ void TableRelativePermeabilityHysteresis::postInputInitialization()
"the expected number of fluid phases is either two, or three",
InputError, getDataContext() );
- m_phaseMinVolumeFraction.resize( numPhases );
m_phaseHasHysteresis.resize( numPhases );
//initialize STONE-II only used var to avoid discrepancies in baselines
@@ -222,13 +242,14 @@ void TableRelativePermeabilityHysteresis::postInputInitialization()
}
GEOS_THROW_IF( m_phaseHasHysteresis[IPT::WETTING] == 0 && m_phaseHasHysteresis[IPT::NONWETTING] == 0,
- GEOS_FMT( "we must use {} or {} to specify at least one imbibition relative permeability table",
+ GEOS_FMT( "{}: we must use {} or {} to specify at least one imbibition relative permeability table",
+ getFullName(),
viewKeyStruct::imbibitionWettingRelPermTableNameString(),
viewKeyStruct::imbibitionNonWettingRelPermTableNameString() ),
InputError, getDataContext() );
//Killough section
- KilloughHysteresis::postProcessInput( m_jerauldParam_a, m_jerauldParam_b, m_killoughCurvatureParamRelPerm );
+ KilloughHysteresis::postProcessInput( m_jerauldParam_a, m_jerauldParam_b, m_killoughCurvatureParamRelPerm, 0.0 );
}
void TableRelativePermeabilityHysteresis::initializePreSubGroups()
@@ -255,70 +276,65 @@ void TableRelativePermeabilityHysteresis::checkExistenceAndValidateWettingRelPer
using IPT = TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType;
integer const numPhases = m_phaseNames.size();
integer ipWetting = -1, ipNonWetting = -1;
- std::tie( ipWetting, ipNonWetting ) = RelativePermeabilityBase::wettingAndNonWettingPhaseIndices();
+ std::tie( ipWetting, ipNonWetting ) = RelativePermeabilityBase::phaseIndex( m_phaseOrder );
// Step 1.a: take care of the two-phase case
- real64 drainagePhaseMinVolFraction = -1; // output
- real64 drainagePhaseMaxVolFraction = -1;
- real64 drainagePhaseRelPermMinEndPoint = -1;
- real64 drainagePhaseRelPermMaxEndPoint = -1;
-
- string const tableName = ( numPhases == 2 ) ?
- m_drainageWettingNonWettingRelPermTableNames[0] : m_drainageWettingIntermediateRelPermTableNames[0];
-
- checkExistenceAndValidateRelPermTable( tableName, // input
- drainagePhaseMinVolFraction, // output
+ real64 drainagePhaseMinVolFraction, // output
+ drainagePhaseMaxVolFraction,
+ drainagePhaseRelPermMinEndPoint,
+ drainagePhaseRelPermMaxEndPoint;
+ GEOS_ASSERT( m_drainageWettingNonWettingRelPermTableNames.size() == 2 );
+ auto tableName = ( numPhases == 2 ) ? m_drainageWettingNonWettingRelPermTableNames[0] : m_drainageWettingIntermediateRelPermTableNames[0];
+// integer const ipWetting = ( m_phaseOrder[PhaseType::WATER] >= 0 ) ? m_phaseOrder[PhaseType::WATER] : m_phaseOrder[PhaseType::OIL];
+ checkExistenceAndValidateRelPermTable( tableName, // input
+ drainagePhaseMinVolFraction, // output
drainagePhaseMaxVolFraction,
drainagePhaseRelPermMinEndPoint,
drainagePhaseRelPermMaxEndPoint );
- // imbibition if provided
- real64 imbibitionPhaseMinVolFraction = drainagePhaseMinVolFraction; // output
- real64 imbibitionPhaseMaxVolFraction = drainagePhaseMaxVolFraction;
- real64 imbibitionPhaseRelPermMinEndPoint = drainagePhaseRelPermMinEndPoint;
- real64 imbibitionPhaseRelPermMaxEndPoint = drainagePhaseRelPermMaxEndPoint;
+
+ //imbibition if provided
+ real64 imbibitionPhaseMinVolFraction, // output
+ imbibitionPhaseMaxVolFraction,
+ imbibitionPhaseRelPermMinEndPoint,
+ imbibitionPhaseRelPermMaxEndPoint;
if( m_phaseHasHysteresis[IPT::WETTING] )
{
- checkExistenceAndValidateRelPermTable( m_imbibitionWettingRelPermTableName, // input
- imbibitionPhaseMinVolFraction, // output
+ checkExistenceAndValidateRelPermTable( m_imbibitionWettingRelPermTableName, // input
+ imbibitionPhaseMinVolFraction, // output
imbibitionPhaseMaxVolFraction,
imbibitionPhaseRelPermMinEndPoint,
imbibitionPhaseRelPermMaxEndPoint );
GEOS_THROW_IF( !isZero( imbibitionPhaseMinVolFraction - drainagePhaseMinVolFraction ),
- GEOS_FMT( "the critical wetting-phase volume fraction (saturation) must be the same in drainage and imbibition.\n"
+ GEOS_FMT( "{}: the critical wetting-phase volume fraction (saturation) must be the same in drainage and imbibition.\n"
"However, we found that the drainage critical wetting-phase volume fraction is {}, "
"whereas the imbibition critical wetting-phase volume fraction is {}",
+ getFullName(),
drainagePhaseMinVolFraction, imbibitionPhaseMinVolFraction ),
InputError, getDataContext() );
GEOS_THROW_IF( imbibitionPhaseMaxVolFraction > drainagePhaseMaxVolFraction,
- GEOS_FMT( "the maximum wetting-phase volume fraction (saturation) must be smaller in imbibition (compared to the drainage value).\n"
+ GEOS_FMT( "{}: the maximum wetting-phase volume fraction (saturation) must be smaller in imbibition (compared to the drainage value).\n"
"However, we found that the drainage maximum wetting-phase volume fraction is {}, "
"whereas the imbibition maximum wetting-phase volume fraction is {}",
+ getFullName(),
drainagePhaseMaxVolFraction, imbibitionPhaseMaxVolFraction ),
InputError, getDataContext() );
GEOS_THROW_IF( imbibitionPhaseRelPermMaxEndPoint > drainagePhaseRelPermMaxEndPoint,
- GEOS_FMT( "the maximum wetting-phase relperm must be smaller in imbibition (compared to the drainage value).\n"
+ GEOS_FMT( "{}: the maximum wetting-phase relperm must be smaller in imbibition (compared to the drainage value).\n"
"However, we found that the drainage maximum wetting-phase relperm is {}, "
"whereas the imbibition maximum wetting-phase relperm is {}",
+ getFullName(),
drainagePhaseRelPermMaxEndPoint, imbibitionPhaseRelPermMaxEndPoint ),
InputError, getDataContext() );
}
- m_wettingCurve.setPoints( drainagePhaseMinVolFraction, drainagePhaseRelPermMinEndPoint, // same as imbibition min
- imbibitionPhaseMaxVolFraction, imbibitionPhaseRelPermMaxEndPoint,
- drainagePhaseMaxVolFraction, drainagePhaseRelPermMaxEndPoint );
-
- m_phaseMinVolumeFraction[ipWetting] = drainagePhaseMinVolFraction;
-
- GEOS_LOG_LEVEL_RANK_0( logInfo::Init, GEOS_FMT( "Initializing wetting relperm curve with {(smin,krmin), (simax,krimax), (sdmax,krdmax)} : {({},{}),({},{}),({},{})}",
- m_wettingCurve.m_extremumPhaseVolFraction, m_wettingCurve.m_extremumValue,
- m_wettingCurve.m_criticalImbibitionPhaseVolFraction, m_wettingCurve.m_criticalImbibitionValue,
- m_wettingCurve.m_criticalDrainagePhaseVolFraction, m_wettingCurve.m_criticalDrainageValue
- ));
+ m_wettingCurve.setPoints( {drainagePhaseMinVolFraction, drainagePhaseRelPermMinEndPoint}, // extremum
+ {imbibitionPhaseMaxVolFraction, imbibitionPhaseRelPermMaxEndPoint}, // imbibition critical
+ {drainagePhaseMaxVolFraction, drainagePhaseRelPermMaxEndPoint} ); // drainage critical
}
void TableRelativePermeabilityHysteresis::checkExistenceAndValidateNonWettingRelPermTables()
@@ -327,17 +343,17 @@ void TableRelativePermeabilityHysteresis::checkExistenceAndValidateNonWettingRel
integer const numPhases = m_phaseNames.size();
integer ipWetting = -1, ipNonWetting = -1;
- std::tie( ipWetting, ipNonWetting ) = RelativePermeabilityBase::wettingAndNonWettingPhaseIndices();
-
- // treat drainage
- real64 drainagePhaseMinVolFraction = -1; // output
- real64 drainagePhaseMaxVolFraction = -1;
- real64 drainagePhaseRelPermMinEndPoint = -1;
- real64 drainagePhaseRelPermMaxEndPoint = -1;
+ std::tie( ipWetting, ipNonWetting ) = RelativePermeabilityBase::phaseIndex( m_phaseOrder );
+ //treat drainage
+ real64 drainagePhaseMinVolFraction, // output
+ drainagePhaseMaxVolFraction,
+ drainagePhaseRelPermMinEndPoint,
+ drainagePhaseRelPermMaxEndPoint;
// Step 1: Read the drainage for the non wetting phase
- string const tableName = ( numPhases == 2 ) ? m_drainageWettingNonWettingRelPermTableNames[1] :
- m_drainageNonWettingIntermediateRelPermTableNames[0];
+ GEOS_ASSERT( m_drainageWettingNonWettingRelPermTableNames.size() == 2 );
+ auto tableName = ( numPhases == 2 ) ? m_drainageWettingNonWettingRelPermTableNames[1] :
+ m_drainageNonWettingIntermediateRelPermTableNames[0];
checkExistenceAndValidateRelPermTable( tableName, // input
drainagePhaseMinVolFraction, // output
drainagePhaseMaxVolFraction,
@@ -345,10 +361,10 @@ void TableRelativePermeabilityHysteresis::checkExistenceAndValidateNonWettingRel
drainagePhaseRelPermMaxEndPoint );
// Step 2: validate non-wetting-phase imbibition relative permeability table
- real64 imbibitionPhaseMinVolFraction = drainagePhaseMinVolFraction; // output
- real64 imbibitionPhaseMaxVolFraction = drainagePhaseMaxVolFraction;
- real64 imbibitionPhaseRelPermMinEndPoint = drainagePhaseRelPermMinEndPoint;
- real64 imbibitionPhaseRelPermMaxEndPoint = drainagePhaseRelPermMaxEndPoint;
+ real64 imbibitionPhaseMinVolFraction, // output
+ imbibitionPhaseMaxVolFraction,
+ imbibitionPhaseRelPermMinEndPoint,
+ imbibitionPhaseRelPermMaxEndPoint;
if( m_phaseHasHysteresis[IPT::NONWETTING] )
{
@@ -360,39 +376,35 @@ void TableRelativePermeabilityHysteresis::checkExistenceAndValidateNonWettingRel
imbibitionPhaseRelPermMaxEndPoint );
GEOS_THROW_IF( !isZero ( imbibitionPhaseMaxVolFraction - drainagePhaseMaxVolFraction ),
- GEOS_FMT( string( "the maximum non-wetting-phase volume fraction (saturation) must be the same in drainage and imbibition.\n" )
+ GEOS_FMT( string( "{}: the maximum non-wetting-phase volume fraction (saturation) must be the same in drainage and imbibition.\n" )
+ string( "However, we found that the drainage maximum wetting-phase volume fraction is {}, " )
+ string( "whereas the imbibition maximum wetting-phase volume fraction is {}" ),
+ getFullName(),
drainagePhaseMaxVolFraction, imbibitionPhaseMaxVolFraction ),
InputError, getDataContext() );
GEOS_THROW_IF( !isZero ( imbibitionPhaseRelPermMaxEndPoint - drainagePhaseRelPermMaxEndPoint ),
- GEOS_FMT( string( "the non-wetting-phase relperm endpoint must be the same in drainage and imbibition.\n" )
+ GEOS_FMT( string( "{}: the non-wetting-phase relperm endpoint must be the same in drainage and imbibition.\n" )
+ string( "However, we found that the drainage endpoint wetting-phase relperm is {}, " )
+ string( "whereas the imbibition endpoint wetting-phase relperm is {}" ),
+ getFullName(),
drainagePhaseRelPermMaxEndPoint, imbibitionPhaseRelPermMaxEndPoint ),
InputError, getDataContext() );
GEOS_THROW_IF( imbibitionPhaseMinVolFraction < drainagePhaseMinVolFraction,
- GEOS_FMT( string( "the critical wetting-phase volume fraction (saturation) must be larger in imbibition (compared to the drainage value).\n" )
+ GEOS_FMT( string( "{}: the critical wetting-phase volume fraction (saturation) must be larger in imbibition (compared to the drainage value).\n" )
+ string( "However, we found that the drainage critical wetting-phase volume fraction is {}, " )
+ string( "whereas the imbibition critical wetting-phase volume fraction is {}" ),
+ getFullName(),
drainagePhaseMinVolFraction, imbibitionPhaseMinVolFraction ),
InputError, getDataContext() );
}
- m_nonWettingCurve.setPoints( drainagePhaseMaxVolFraction, drainagePhaseRelPermMaxEndPoint, // same as imbibition max
- imbibitionPhaseMinVolFraction, imbibitionPhaseRelPermMinEndPoint,
- drainagePhaseMinVolFraction, drainagePhaseRelPermMinEndPoint );
-
- m_phaseMinVolumeFraction[ipNonWetting] = drainagePhaseMinVolFraction;
- GEOS_LOG_LEVEL_RANK_0( logInfo::Init, GEOS_FMT( "Initializing non-wetting relperm curve with {(sdmin,krdmin), (simin,krimin), (smax,krmax)} : {({},{}),({},{}),({},{})}",
- m_nonWettingCurve.m_criticalDrainagePhaseVolFraction, m_nonWettingCurve.m_criticalDrainageValue,
- m_nonWettingCurve.m_criticalImbibitionPhaseVolFraction, m_nonWettingCurve.m_criticalImbibitionValue,
- m_nonWettingCurve.m_extremumPhaseVolFraction, m_nonWettingCurve.m_extremumValue
- ));
+ m_nonWettingCurve.setPoints( {drainagePhaseMaxVolFraction, drainagePhaseRelPermMaxEndPoint}, // extremum
+ {imbibitionPhaseMinVolFraction, imbibitionPhaseRelPermMinEndPoint}, // imbibition critical
+ {drainagePhaseMinVolFraction, drainagePhaseRelPermMinEndPoint} ); // drainage critical
}
@@ -401,19 +413,21 @@ void TableRelativePermeabilityHysteresis::checkExistenceAndValidateIntermediateR
if( m_phaseNames.size() == 3 )
{
- real64 drainagePhaseMinVolFraction,
+
+ real64 drainagePhaseMinVolFraction, //
drainagePhaseMaxVolFraction,
drainagePhaseRelPermMinEndPoint,
drainagePhaseRelPermMaxEndPoint;
- // intermediate drainage from wetting
+ //intermediate drainage from wetting
checkExistenceAndValidateRelPermTable( m_drainageWettingIntermediateRelPermTableNames[1], // input
drainagePhaseMinVolFraction, // output
drainagePhaseMaxVolFraction,
drainagePhaseRelPermMinEndPoint,
drainagePhaseRelPermMaxEndPoint );
+ //??
checkExistenceAndValidateRelPermTable( m_drainageNonWettingIntermediateRelPermTableNames[1], // input
drainagePhaseMinVolFraction,
drainagePhaseMaxVolFraction,
@@ -454,9 +468,8 @@ void TableRelativePermeabilityHysteresis::computeLandCoefficient()
// For two-phase flow, we make sure that they are equal
m_landParam.resize( 2 );
- // Note: for simplicity, the notations are taken classical reservoir notations (although this breaks our phaseVolFrac naming convention)
+ // Note: for simplicity, the notations are taken reservoir simulation literature (although this breaks our phaseVolFrac naming convention)
using IPT = TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType;
-
KilloughHysteresis::computeLandCoefficient( m_wettingCurve, m_landParam[IPT::WETTING] );
KilloughHysteresis::computeLandCoefficient( m_nonWettingCurve, m_landParam[IPT::NONWETTING] );
}
@@ -552,12 +565,14 @@ void TableRelativePermeabilityHysteresis::allocateConstitutiveData( Group & pare
{
integer const numPhases = numFluidPhases();
- m_phaseMinVolumeFraction.resize( numPhases );
- m_phaseMaxHistoricalVolFraction.resize( 0, numPhases );
- m_phaseMinHistoricalVolFraction.resize( 0, numPhases );
-
RelativePermeabilityBase::allocateConstitutiveData( parent, numPts );
+ m_phaseMaxHistoricalVolFraction.resize( parent.size(), numPhases );
+ m_phaseMinHistoricalVolFraction.resize( parent.size(), numPhases );
+
+ m_phaseMaxHistoricalVolFraction.setValues< parallelDevicePolicy<> >( 0.0 );
+ m_phaseMinHistoricalVolFraction.setValues< parallelDevicePolicy<> >( 1.0 );
+
m_phaseMaxHistoricalVolFraction.setValues< parallelDevicePolicy<> >( 0.0 );
m_phaseMinHistoricalVolFraction.setValues< parallelDevicePolicy<> >( 1.0 );
}
@@ -583,24 +598,25 @@ void TableRelativePermeabilityHysteresis::saveConvergedPhaseVolFractionState( ar
}
-TableRelativePermeabilityHysteresis::KernelWrapper::KernelWrapper( arrayView1d< TableFunction::KernelWrapper const > const & drainageRelPermKernelWrappers,
- arrayView1d< TableFunction::KernelWrapper const > const & imbibitionRelPermKernelWrappers,
- arrayView1d< integer const > const & phaseHasHysteresis,
- arrayView1d< real64 const > const & landParam,
- real64 const & jerauldParam_a,
- real64 const & jerauldParam_b,
- real64 const & killoughCurvatureParamRelPerm,
- KilloughHysteresis::HysteresisCurve const & wettingCurve,
- KilloughHysteresis::HysteresisCurve const & nonWettingCurve,
- arrayView1d< integer const > const & phaseTypes,
- arrayView1d< integer const > const & phaseOrder,
- ThreePhaseInterpolator const & threePhaseInterpolator,
- real64 const & waterOilRelPermMaxValue,
- arrayView2d< real64 const, compflow::USD_PHASE > const & phaseMinHistoricalVolFraction,
- arrayView2d< real64 const, compflow::USD_PHASE > const & phaseMaxHistoricalVolFraction,
- arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac,
- arrayView3d< real64, relperm::USD_RELPERM > const & phaseRelPerm,
- arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac )
+TableRelativePermeabilityHysteresis::KernelWrapper::
+ KernelWrapper( arrayView1d< TableFunction::KernelWrapper const > const & drainageRelPermKernelWrappers,
+ arrayView1d< TableFunction::KernelWrapper const > const & imbibitionRelPermKernelWrappers,
+ arrayView1d< integer const > const & phaseHasHysteresis,
+ arrayView1d< real64 const > const & landParam,
+ real64 const & jerauldParam_a,
+ real64 const & jerauldParam_b,
+ real64 const & killoughCurvatureParamRelPerm,
+ KilloughHysteresis::HysteresisCurve const & wettingCurve,
+ KilloughHysteresis::HysteresisCurve const & nonWettingCurve,
+ arrayView1d< integer const > const & phaseTypes,
+ arrayView1d< integer const > const & phaseOrder,
+ ThreePhaseInterpolator const & threePhaseInterpolator,
+ real64 const & waterOilRelPermMaxValue,
+ arrayView2d< real64 const, compflow::USD_PHASE > const & phaseMinHistoricalVolFraction,
+ arrayView2d< real64 const, compflow::USD_PHASE > const & phaseMaxHistoricalVolFraction,
+ arrayView3d< real64, relperm::USD_RELPERM > const & phaseTrappedVolFrac,
+ arrayView3d< real64, relperm::USD_RELPERM > const & phaseRelPerm,
+ arrayView4d< real64, relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac )
:
RelativePermeabilityBaseUpdate( phaseTypes,
phaseOrder,
diff --git a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.hpp b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.hpp
index 3f0d5611f4c..6cd17ba3af5 100644
--- a/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.hpp
+++ b/src/coreComponents/constitutive/relativePermeability/TableRelativePermeabilityHysteresis.hpp
@@ -21,12 +21,11 @@
#define GEOS_CONSTITUTIVE_TABLERELATIVEPERMEABILITYHYSTERESIS_HPP
-#include "constitutive/relativePermeability/KilloughHysteresis.hpp"
+#include "constitutive/KilloughHysteresis.hpp"
#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp"
#include "constitutive/relativePermeability/RelativePermeabilityInterpolators.hpp"
#include "functions/TableFunction.hpp"
-
-
+///helper model class with data struct for curves and computing recipe for trapped and Land Coeff
namespace geos
{
@@ -79,8 +78,6 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase
virtual string getCatalogName() const override { return catalogName(); }
- virtual void allocateConstitutiveData( dataRepository::Group & parent, localIndex const numPts ) override;
-
/// Type of kernel wrapper for in-kernel update
class KernelWrapper final : public RelativePermeabilityBaseUpdate
{
@@ -140,7 +137,24 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase
real64 & phaseRelPerm,
real64 & dPhaseRelPerm_dPhaseVolFrac ) const;
-
+ /**
+ * @brief Function computing the trapped critical phase volume fraction (Sgcrt)
+ * @param[in] Scrd the drainage critical phase volume fraction
+ * @param[in] Shy the max historical phase volume fraction
+ * @param[in] Smx the max phase volume fraction (= end-point phase volume fraction)
+ * @param[in] jerauldParam_a first (modification) parameter proposed by Jerauld
+ * @param[in] jerauldParam_b second (exponent) parameter proposed by Jerauld
+ * @param[in] landParam Land trapping parameter
+ * @param[out] Scrt the trapped critical phase volume fraction
+ */
+ GEOS_HOST_DEVICE
+ void computeTrappedCriticalPhaseVolFraction( real64 const & Scrd,
+ real64 const & Shy,
+ real64 const & Smx,
+ real64 const & jerauldParam_a,
+ real64 const & jerauldParam_b,
+ real64 const & landParam,
+ real64 & Scrt ) const;
/**
* @brief Function updating the relperm (and derivative) for the wetting phase in imbibition using Killough's method
* @param[in] drainageRelPermKernelWrapper kernel wrapper storing the drainage relperm table for the wetting phase
@@ -270,19 +284,13 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase
/// Trapping parameter from the Land model (typically called C)
arrayView1d< real64 const > m_landParam;
- /// Parameter a introduced by Jerauld in the Land model
real64 const & m_jerauldParam_a;
- /// Parameter b introduced by Jerauld in the Land model
real64 const & m_jerauldParam_b;
- /// Curvature parameter introduced for wetting phase hysteresis in Killough
real64 const & m_killoughCurvatureParamRelPerm;
- /// The wetting phase hysteretic curve
KilloughHysteresis::HysteresisCurve const & m_wettingCurve;
-
- /// The non-wetting phase hysteretic curve
KilloughHysteresis::HysteresisCurve const & m_nonWettingCurve;
/// Minimum historical phase volume fraction for each phase
@@ -307,17 +315,17 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase
struct viewKeyStruct : RelativePermeabilityBase::viewKeyStruct
{
- /// Land coefficient
+ ///Land Coeff
static constexpr char const * landParameterString() { return "landParameter"; }
- /// Hysteretic curves
+ ///and packed curves data struct
static constexpr char const * wettingCurveString() { return "wettingCurve"; };
static constexpr char const * nonWettingCurveString() { return "nonWettingCurve"; };
- /// Flag to determine whether a phase has hysteresis or not
+ ///flag
static constexpr char const * phaseHasHysteresisString() { return "phaseHasHysteresis"; }
- /// Tables and associated wrappers
+ ///tables and assoc. wrappers
static constexpr char const * drainageRelPermKernelWrappersString() { return "drainageRelPermWrappers"; }
static constexpr char const * imbibitionRelPermKernelWrappersString() { return "imbibitionRelPermWrappers"; }
@@ -334,18 +342,18 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase
};
- arrayView1d< real64 const > getPhaseMinVolumeFraction() const override { return m_phaseMinVolumeFraction; };
-
real64 getWettingPhaseMinVolumeFraction() const override
{
- return m_wettingCurve.m_extremumPhaseVolFraction;
+ return m_wettingCurve.oppositeBoundPhaseVolFraction;
}
real64 getNonWettingMinVolumeFraction() const override
{
- return m_nonWettingCurve.m_criticalDrainagePhaseVolFraction;
+ return m_nonWettingCurve.oppositeBoundPhaseVolFraction;
}
+ virtual void allocateConstitutiveData( Group & parent, localIndex const numPts ) override;
+
private:
virtual void postInputInitialization() override;
@@ -453,17 +461,10 @@ class TableRelativePermeabilityHysteresis : public RelativePermeabilityBase
/// Maximum historical phase volume fraction for each phase
array2d< real64, compflow::LAYOUT_PHASE > m_phaseMaxHistoricalVolFraction;
- /// The wetting phase hysteretic curve
KilloughHysteresis::HysteresisCurve m_wettingCurve;
-
- /// The non-wetting phase hysteretic curve
KilloughHysteresis::HysteresisCurve m_nonWettingCurve;
- /// Min phase volume fractions (deduced from the tables). With Baker, only the water phase entry is used
- array1d< real64 > m_phaseMinVolumeFraction;
-
real64 m_waterOilMaxRelPerm;
-
ThreePhaseInterpolator m_threePhaseInterpolator;
};
@@ -498,13 +499,13 @@ TableRelativePermeabilityHysteresis::KernelWrapper::
// if consistent, S should be equal to 1 - imbibitionPhaseMinVolNonWettingFraction for two-phase flow
// (but wetting and nonwetting phase hysteresis are implemented in a decoupled fashion)
real64 const S = phaseVolFraction;
- real64 const Smxi = m_wettingCurve.m_criticalImbibitionPhaseVolFraction;
- real64 const Smxd = m_wettingCurve.m_criticalDrainagePhaseVolFraction;
+ real64 const Smxi = m_wettingCurve.imbibitionExtremaPhaseVolFraction;
+ real64 const Smxd = m_wettingCurve.drainageExtremaPhaseVolFraction;
// Swc is the common end min endpoint saturation for wetting curves
- real64 const Swc = m_wettingCurve.m_extremumPhaseVolFraction;
+ real64 const Swc = m_wettingCurve.oppositeBoundPhaseVolFraction;
- using IPT = ImbibitionPhasePairPhaseType;
+ using IPT = TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType;
if( S <= Swc )
{
phaseRelPerm = 0.0;
@@ -512,12 +513,12 @@ TableRelativePermeabilityHysteresis::KernelWrapper::
}
else if( S >= Smxd )
{
- phaseRelPerm = m_wettingCurve.m_criticalDrainageValue;
+ phaseRelPerm = m_wettingCurve.drainageExtremaSCALValue;
dPhaseRelPerm_dPhaseVolFrac = 0.0;
}
else
{
- real64 const krwei = m_wettingCurve.m_criticalImbibitionValue;
+ real64 const krwei = m_wettingCurve.imbibitionExtremaSCALValue;
real64 const krwedAtSmxi = drainageRelPermKernelWrapper.compute( &Smxi );
// Step 1: Compute the new end point
@@ -578,12 +579,12 @@ TableRelativePermeabilityHysteresis::KernelWrapper::
// Step 1: for a given value of the max historical saturation, Shy, compute the trapped critical saturation, Scrt,
// using Land's method. The calculation includes the modifications from Jerauld.
real64 const S = phaseVolFraction;
- real64 const Scri = m_nonWettingCurve.m_criticalImbibitionPhaseVolFraction;
- real64 const Smx = m_nonWettingCurve.m_extremumPhaseVolFraction;
+ real64 const Scri = m_nonWettingCurve.imbibitionExtremaPhaseVolFraction;
+ real64 const Smx = m_nonWettingCurve.oppositeBoundPhaseVolFraction;
real64 const Shy = (phaseMaxHistoricalVolFraction < Smx) ? phaseMaxHistoricalVolFraction : Smx; // to make sure that Shy < Smax
real64 Scrt = 0;
- using IPT = ImbibitionPhasePairPhaseType;
+ using IPT = TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType;
KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve,
Shy,
m_landParam[IPT::NONWETTING],
@@ -598,13 +599,13 @@ TableRelativePermeabilityHysteresis::KernelWrapper::
}
else if( S >= Smx ) // S is above the max saturation, so we just skip the rest and set the relperm to the endpoint
{
- phaseRelPerm = m_nonWettingCurve.m_extremumValue;
+ phaseRelPerm = m_nonWettingCurve.oppositeBoundSCALValue;
dPhaseRelPerm_dPhaseVolFrac = 0.0;
}
else
{
// Step 2: compute the normalized saturation, S_norm, at which the imbibition relperm curve will be evaluated.
- real64 const ratio = ( Smx - Scri ) / ( Shy - Scrt );
+ real64 const ratio = ( Smx - Scri ) / ( Shy - Scrt ); // non S-deps part (isolated for derivatives calculations)
real64 const Snorm = Scri + ( S - Scrt ) * ratio; // normalized saturation
real64 const dSnorm_dS = ratio;
@@ -618,7 +619,7 @@ TableRelativePermeabilityHysteresis::KernelWrapper::
real64 const krdAtShy = drainageRelPermKernelWrapper.compute( &Shy );
// Step 5: evaluate the drainage relperm, krd(Smx), at the max drainage saturation, Smx.
- real64 const krdAtSmx = m_nonWettingCurve.m_extremumValue;
+ real64 const krdAtSmx = m_nonWettingCurve.oppositeBoundSCALValue;
// Step 6: apply the formula blending drainage and imbibition relperms from the Killough model.
real64 const drainageRelPermRatio = krdAtShy / krdAtSmx;
@@ -646,11 +647,29 @@ TableRelativePermeabilityHysteresis::KernelWrapper::
using TPT = constitutive::TableRelativePermeabilityHysteresis::TwoPhasePairPhaseType;
using IPT = constitutive::TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType;
+ constexpr bool FORCE_IMBIBITION_MODE = false;
+ constexpr bool FORCE_DRAINAGE_MODE = false;
+
// ---------- wetting rel perm
- if( !m_phaseHasHysteresis[IPT::WETTING] ||
- phaseVolFraction[ipWetting] <= phaseMinHistoricalVolFraction[ipWetting] + flowReversalBuffer )
+ if( FORCE_DRAINAGE_MODE )
+ {
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( phaseVolFraction[ipWetting], m_wettingCurve.oppositeBoundPhaseVolFraction );
+ computeDrainageRelPerm( m_drainageRelPermKernelWrappers[TPT::WETTING],
+ phaseVolFraction[ipWetting],
+ phaseRelPerm[ipWetting],
+ dPhaseRelPerm_dPhaseVolFrac[ipWetting][ipWetting] );
+ }
+ else if( FORCE_IMBIBITION_MODE )
{
- phaseTrappedVolFrac[ipWetting] = LvArray::math::min( phaseVolFraction[ipWetting], m_wettingCurve.m_extremumPhaseVolFraction );
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( phaseVolFraction[ipWetting], m_wettingCurve.oppositeBoundPhaseVolFraction );
+ auto const & imbibitionRelPermKernelWrapper = m_imbibitionRelPermKernelWrappers[IPT::WETTING];
+ phaseRelPerm[ipWetting] = imbibitionRelPermKernelWrapper.compute( &phaseVolFraction[ipWetting],
+ &dPhaseRelPerm_dPhaseVolFrac[ipWetting][ipWetting] );
+ }
+ else if( !m_phaseHasHysteresis[IPT::WETTING] ||
+ phaseVolFraction[ipWetting] <= phaseMinHistoricalVolFraction[ipWetting] + flowReversalBuffer )
+ {
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( phaseVolFraction[ipWetting], m_wettingCurve.oppositeBoundPhaseVolFraction );
computeDrainageRelPerm( m_drainageRelPermKernelWrappers[TPT::WETTING],
phaseVolFraction[ipWetting],
phaseRelPerm[ipWetting],
@@ -667,12 +686,37 @@ TableRelativePermeabilityHysteresis::KernelWrapper::
}
// --------- non-wetting rel perm
- if( !m_phaseHasHysteresis[IPT::NONWETTING] ||
- phaseVolFraction[ipNonWetting] >= phaseMaxHistoricalVolFraction[ipNonWetting] - flowReversalBuffer )
+ if( FORCE_DRAINAGE_MODE )
+ {
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( phaseVolFraction[ipNonWetting], m_nonWettingCurve.drainageExtremaPhaseVolFraction );
+ computeDrainageRelPerm( m_drainageRelPermKernelWrappers[TPT::NONWETTING],
+ phaseVolFraction[ipNonWetting],
+ phaseRelPerm[ipNonWetting],
+ dPhaseRelPerm_dPhaseVolFrac[ipNonWetting][ipNonWetting] );
+ }
+ else if( FORCE_IMBIBITION_MODE )
+ {
+ real64 const Shy = ( phaseVolFraction[ipNonWetting] < m_nonWettingCurve.oppositeBoundPhaseVolFraction )
+ ? phaseVolFraction[ipNonWetting] : m_nonWettingCurve.oppositeBoundPhaseVolFraction;
+ real64 Scrt = 0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve,
+ Shy,
+ m_landParam[IPT::NONWETTING],
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipNonWetting] );
+
+ auto const & imbibitionRelPermKernelWrapper = m_imbibitionRelPermKernelWrappers[IPT::NONWETTING];
+ phaseRelPerm[ipNonWetting] = imbibitionRelPermKernelWrapper.compute( &phaseVolFraction[ipNonWetting],
+ &dPhaseRelPerm_dPhaseVolFrac[ipNonWetting][ipNonWetting] );
+ }
+ else if( !m_phaseHasHysteresis[IPT::NONWETTING] ||
+ phaseVolFraction[ipNonWetting] >= phaseMaxHistoricalVolFraction[ipNonWetting] - flowReversalBuffer )
{
// for reporting purposes, compute Sgcrt first
- real64 const Shy = ( phaseVolFraction[ipNonWetting] < m_nonWettingCurve.m_extremumPhaseVolFraction )
- ? phaseVolFraction[ipNonWetting] : m_nonWettingCurve.m_extremumPhaseVolFraction; // to make sure that Shy < Smax
+ real64 const Shy = ( phaseVolFraction[ipNonWetting] < m_nonWettingCurve.oppositeBoundPhaseVolFraction )
+ ? phaseVolFraction[ipNonWetting] : m_nonWettingCurve.oppositeBoundPhaseVolFraction; // to make sure that Shy < Smax
real64 Scrt = 0;
KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve,
Shy,
@@ -721,13 +765,31 @@ TableRelativePermeabilityHysteresis::KernelWrapper::
using TPT = constitutive::TableRelativePermeabilityHysteresis::ThreePhasePairPhaseType;
using IPT = constitutive::TableRelativePermeabilityHysteresis::ImbibitionPhasePairPhaseType;
+ constexpr bool FORCE_IMBIBITION_MODE = false;
+ constexpr bool FORCE_DRAINAGE_MODE = false;
+
// 1) Wetting and intermediate phase relative permeabilities using two-phase wetting-intermediate data
// ---------- wetting rel perm
- if( !m_phaseHasHysteresis[IPT::WETTING] ||
- phaseVolFraction[ipWetting] <= phaseMinHistoricalVolFraction[ipWetting] + flowReversalBuffer )
+ if( FORCE_DRAINAGE_MODE )
+ {
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( m_wettingCurve.oppositeBoundPhaseVolFraction, phaseVolFraction[ipWetting] );
+ computeDrainageRelPerm( m_drainageRelPermKernelWrappers[TPT::WETTING],
+ phaseVolFraction[ipWetting],
+ phaseRelPerm[ipWetting],
+ dPhaseRelPerm_dPhaseVolFrac[ipWetting][ipWetting] );
+ }
+ else if( FORCE_IMBIBITION_MODE )
+ {
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( m_wettingCurve.oppositeBoundPhaseVolFraction, phaseVolFraction[ipWetting] );
+ auto const & imbibitionRelPermKernelWrapper = m_imbibitionRelPermKernelWrappers[IPT::WETTING];
+ phaseRelPerm[ipWetting] = imbibitionRelPermKernelWrapper.compute( &phaseVolFraction[ipWetting],
+ &dPhaseRelPerm_dPhaseVolFrac[ipWetting][ipWetting] );
+ }
+ else if( !m_phaseHasHysteresis[IPT::WETTING] ||
+ phaseVolFraction[ipWetting] <= phaseMinHistoricalVolFraction[ipWetting] + flowReversalBuffer )
{
- phaseTrappedVolFrac[ipWetting] = LvArray::math::min( m_wettingCurve.m_extremumPhaseVolFraction, phaseVolFraction[ipWetting] );
+ phaseTrappedVolFrac[ipWetting] = LvArray::math::min( m_wettingCurve.oppositeBoundPhaseVolFraction, phaseVolFraction[ipWetting] );
computeDrainageRelPerm( m_drainageRelPermKernelWrappers[TPT::WETTING],
phaseVolFraction[ipWetting],
phaseRelPerm[ipWetting],
@@ -752,12 +814,37 @@ TableRelativePermeabilityHysteresis::KernelWrapper::
// 2) Non-wetting and intermediate phase relative permeabilities using two-phase non-wetting-intermediate data
// ---------- non-wetting rel perm
- if( !m_phaseHasHysteresis[IPT::NONWETTING] ||
- phaseVolFraction[ipNonWetting] >= phaseMaxHistoricalVolFraction[ipNonWetting] - flowReversalBuffer )
+ if( FORCE_DRAINAGE_MODE )
+ {
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( m_nonWettingCurve.drainageExtremaPhaseVolFraction, phaseVolFraction[ipNonWetting] );
+ computeDrainageRelPerm( m_drainageRelPermKernelWrappers[TPT::NONWETTING],
+ phaseVolFraction[ipNonWetting],
+ phaseRelPerm[ipNonWetting],
+ dPhaseRelPerm_dPhaseVolFrac[ipNonWetting][ipNonWetting] );
+ }
+ else if( FORCE_IMBIBITION_MODE )
+ {
+ real64 const Shy = ( phaseVolFraction[ipNonWetting] < m_nonWettingCurve.oppositeBoundPhaseVolFraction)
+ ? phaseVolFraction[ipNonWetting] : m_nonWettingCurve.oppositeBoundPhaseVolFraction;
+ real64 Scrt = 0;
+ KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve,
+ Shy,
+ m_landParam[IPT::NONWETTING],
+ m_jerauldParam_a,
+ m_jerauldParam_b,
+ Scrt );
+ phaseTrappedVolFrac[ipNonWetting] = LvArray::math::min( Scrt, phaseVolFraction[ipNonWetting] );
+
+ auto const & imbibitionRelPermKernelWrapper = m_imbibitionRelPermKernelWrappers[IPT::NONWETTING];
+ phaseRelPerm[ipNonWetting] = imbibitionRelPermKernelWrapper.compute( &phaseVolFraction[ipNonWetting],
+ &dPhaseRelPerm_dPhaseVolFrac[ipNonWetting][ipNonWetting] );
+ }
+ else if( !m_phaseHasHysteresis[IPT::NONWETTING] ||
+ phaseVolFraction[ipNonWetting] >= phaseMaxHistoricalVolFraction[ipNonWetting] - flowReversalBuffer )
{
// 2.a) compute Sgcrt for reporting purposes
- real64 const Shy = ( phaseVolFraction[ipNonWetting] < m_nonWettingCurve.m_extremumPhaseVolFraction)
- ? phaseVolFraction[ipNonWetting] : m_nonWettingCurve.m_extremumPhaseVolFraction; // to make sure that Shy < Smax
+ real64 const Shy = ( phaseVolFraction[ipNonWetting] < m_nonWettingCurve.oppositeBoundPhaseVolFraction)
+ ? phaseVolFraction[ipNonWetting] : m_nonWettingCurve.oppositeBoundPhaseVolFraction; // to make sure that Shy < Smax
real64 Scrt = 0;
KilloughHysteresis::computeTrappedCriticalPhaseVolFraction( m_nonWettingCurve,
Shy,
@@ -792,7 +879,7 @@ TableRelativePermeabilityHysteresis::KernelWrapper::
// 3) Compute the "three-phase" oil relperm
// use saturation-weighted interpolation
- real64 const shiftedWettingVolFrac = (phaseVolFraction[ipWetting] - m_wettingCurve.m_extremumPhaseVolFraction);
+ real64 const shiftedWettingVolFrac = (phaseVolFraction[ipWetting] - m_wettingCurve.oppositeBoundPhaseVolFraction);
if( m_threePhaseInterpolator == ThreePhaseInterpolator::BAKER )
{
diff --git a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.hpp
index 931f7d35b63..11bd206d906 100644
--- a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.hpp
+++ b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenBakerRelativePermeability.hpp
@@ -140,19 +140,17 @@ class VanGenuchtenBakerRelativePermeability : public RelativePermeabilityBase
};
- arrayView1d< real64 const > getPhaseMinVolumeFraction() const override { return m_phaseMinVolumeFraction; };
-
real64 getWettingPhaseMinVolumeFraction() const override
{
integer ipWetting;
- std::tie( ipWetting, std::ignore ) = wettingAndNonWettingPhaseIndices();
+ std::tie( ipWetting, std::ignore ) = phaseIndex( getPhaseOrder());
return m_phaseMinVolumeFraction[ipWetting];
}
real64 getNonWettingMinVolumeFraction() const override
{
integer ipNonWetting;
- std::tie( std::ignore, ipNonWetting ) = wettingAndNonWettingPhaseIndices();
+ std::tie( std::ignore, ipNonWetting ) = phaseIndex( getPhaseOrder());
return m_phaseMinVolumeFraction[ipNonWetting];
};
diff --git a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.hpp b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.hpp
index 3927764f236..e91e4fb39bd 100644
--- a/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.hpp
+++ b/src/coreComponents/constitutive/relativePermeability/VanGenuchtenStone2RelativePermeability.hpp
@@ -139,7 +139,7 @@ class VanGenuchtenStone2RelativePermeability : public RelativePermeabilityBase
static constexpr char const * volFracScaleString() { return "volFracScale"; }
};
- arrayView1d< real64 const > getPhaseMinVolumeFraction() const override { return m_phaseMinVolumeFraction; };
+ arrayView1d< real64 const > getPhaseMinVolumeFraction() const { return m_phaseMinVolumeFraction; };
real64 getWettingPhaseMinVolumeFraction() const override
{
diff --git a/src/coreComponents/constitutive/relativePermeability/unitTests/constitutiveTestHelpers.hpp b/src/coreComponents/constitutive/relativePermeability/unitTests/constitutiveTestHelpers.hpp
index e2ddfa05933..c5463cca49f 100644
--- a/src/coreComponents/constitutive/relativePermeability/unitTests/constitutiveTestHelpers.hpp
+++ b/src/coreComponents/constitutive/relativePermeability/unitTests/constitutiveTestHelpers.hpp
@@ -32,7 +32,7 @@ namespace geos
{
namespace testing
{
-void fillArray( array1d< real64_array > & arr, std::initializer_list< real64 > const & input_list )
+void fill_array( array1d< real64_array > & arr, std::initializer_list< real64 > const & input_list )
{
arr.resize( 1 );
arr[0].resize( input_list.size());
@@ -42,7 +42,7 @@ void fillArray( array1d< real64_array > & arr, std::initializer_list< real64 > c
}
-void fillArray( real64_array & arr, std::initializer_list< real64 > const & input_list )
+void fill_array( real64_array & arr, std::initializer_list< real64 > const & input_list )
{
arr.resize( input_list.size());
int j = 0;
diff --git a/src/coreComponents/constitutive/unitTests/FluidModelTest_impl.hpp b/src/coreComponents/constitutive/unitTests/FluidModelTest_impl.hpp
index 72cfec6501c..ce731e6b775 100644
--- a/src/coreComponents/constitutive/unitTests/FluidModelTest_impl.hpp
+++ b/src/coreComponents/constitutive/unitTests/FluidModelTest_impl.hpp
@@ -35,7 +35,7 @@ template< typename FLUID_TYPE, integer NUM_COMP, integer NUM_PHASE >
FluidModelTest< FLUID_TYPE, NUM_COMP, NUM_PHASE >::FluidModelTest():
m_parent( "parent", m_node )
{
- createFunctionManager();
+ // createFunctionManager();
}
template< typename FLUID_TYPE, integer NUM_COMP, integer NUM_PHASE >
diff --git a/src/coreComponents/constitutive/unitTests/testTwoPhaseFluid.cpp b/src/coreComponents/constitutive/unitTests/testTwoPhaseFluid.cpp
new file mode 100644
index 00000000000..207668e29cb
--- /dev/null
+++ b/src/coreComponents/constitutive/unitTests/testTwoPhaseFluid.cpp
@@ -0,0 +1,283 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+
+#include "constitutive/fluid/twophasefluid/TwoPhaseFluid.hpp"
+#include "constitutive/fluid/twophasefluid/TwoPhaseFluidFields.hpp"
+
+// Only for fill
+#include "unitTests/constitutiveTests/MultiFluidTest.hpp"
+
+// Only for initializeTable
+#include "unitTests/constitutiveTests/constitutiveTestHelpers.hpp"
+
+
+using namespace geos;
+using namespace geos::testing;
+using namespace geos::constitutive;
+using namespace geos::dataRepository; /// Only for group definition
+
+
+static constexpr char const * tableContentPhase0 = "# Pg(Pa) Dens(kg/m3) Visc(Pa.s)\n"
+ "0.22 0.00603 40203\n"
+ "0.3 0.04224 31311\n"
+ "0.5 0.15011 22423\n"
+ "0.6 0.22423 15011\n"
+ "0.8 0.31311 4224\n"
+ "1.0 0.40203 603";
+
+static constexpr char const * tableContentPhase1 = "# Pg(Pa) Dens(kg/m3) Visc(Pa.s)\n"
+ "1.22 0.00603 0.22\n"
+ "1.3 0.04224 0.22\n"
+ "1.5 0.15011 0.22\n"
+ "1.6 0.22423 0.22\n"
+ "1.8 0.31311 0.22\n"
+ "2.0 0.40203 0.22";
+
+template< bool FROM_TABLE >
+class TwoPhaseFluidTest : public ConstitutiveTestBase< TwoPhaseFluid >
+{
+public:
+
+ TwoPhaseFluidTest()
+ {
+ if constexpr (!FROM_TABLE)
+ {
+ writeTableToFile( "phase0.txt", tableContentPhase0 );
+ writeTableToFile( "phase1.txt", tableContentPhase1 );
+ }
+
+ m_parent.resize( 1 );
+ string const fluidName = GEOS_FMT( "fluid{}", (FROM_TABLE ? "Tables" : "Files"));
+ m_model = makeTwoPhaseFluid( fluidName, m_parent );
+
+ m_parent.initialize();
+ m_parent.initializePostInitialConditions();
+ }
+
+ ~TwoPhaseFluidTest()
+ {
+ if constexpr (!FROM_TABLE)
+ {
+ removeFile( "phase0.txt" );
+ removeFile( "phase1.txt" );
+ }
+ }
+
+ constitutive::TwoPhaseFluid & getFluid() const { return *m_model; }
+
+ dataRepository::Group & getParent() { return m_parent; }
+
+
+ void testDerivatives( constitutive::TwoPhaseFluid & fluid,
+ dataRepository::Group * parent,
+ real64 const pressure,
+ real64 const perturbParameter,
+ real64 const relTol,
+ real64 const absTol = std::numeric_limits< real64 >::max() )
+ {
+ auto const & phaseNames = fluid.getReference< string_array >( TwoPhaseFluid::viewKeyStruct::phaseNamesString() );
+
+ // create a clone of the fluid to run updates on
+ string const fluidCopyName = fluid.getName() + "Copy";
+ std::unique_ptr< constitutive::ConstitutiveBase > fluidCopyPtr = fluid.deliverClone( fluidCopyName, parent );
+ constitutive::TwoPhaseFluid & fluidCopy = dynamicCast< constitutive::TwoPhaseFluid & >( *fluidCopyPtr );
+ fluidCopy.initializePostSubGroups();
+
+ fluid.allocateConstitutiveData( fluid.getParent(), 1 );
+ fluidCopy.allocateConstitutiveData( fluid.getParent(), 1 );
+
+ // extract data views from both fluids
+ #define GET_FLUID_DATA( FLUID, TRAIT ) \
+ FLUID.getReference< TRAIT::type >( TRAIT::key() )[0][0]
+
+ constitutive::MultiFluidVarSlice< real64, 1, constitutive::multifluid::USD_PHASE - 2, constitutive::multifluid::USD_PHASE_DC - 2 > phaseVisc {
+ GET_FLUID_DATA( fluid, fields::twophasefluid::phaseViscosity ),
+ GET_FLUID_DATA( fluid, fields::twophasefluid::dPhaseViscosity )
+ };
+
+ constitutive::MultiFluidVarSlice< real64, 1, constitutive::multifluid::USD_PHASE - 2, constitutive::multifluid::USD_PHASE_DC - 2 > phaseDens {
+ GET_FLUID_DATA( fluid, fields::twophasefluid::phaseDensity ),
+ GET_FLUID_DATA( fluid, fields::twophasefluid::dPhaseDensity )
+ };
+
+ auto const & phaseDensCopy = GET_FLUID_DATA( fluidCopy, fields::twophasefluid::phaseDensity );
+ auto const & phaseViscCopy = GET_FLUID_DATA( fluidCopy, fields::twophasefluid::phaseViscosity );
+#undef GET_FLUID_DATA
+
+
+ // set the original fluid state to current
+ constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid )
+ {
+ typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
+ fluidWrapper.update( 0, 0, pressure );
+ } );
+
+ // now perturb variables and update the copied fluid's state
+ constitutive::constitutiveUpdatePassThru( fluidCopy, [&] ( auto & castedFluid )
+ {
+ using Deriv = constitutive::multifluid::DerivativeOffset;
+
+ typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
+
+ // to be able to use the checkDerivative utility function, we have to invert the layout
+ auto dPhaseDens = invertLayout( phaseDens.derivs.toSliceConst(), 2, 1 );
+ auto dPhaseVisc = invertLayout( phaseVisc.derivs.toSliceConst(), 2, 1 );
+
+ // update pressure and check derivatives
+ real64 const dP = perturbParameter * (pressure + perturbParameter);
+ fluidWrapper.update( 0, 0, pressure + dP );
+
+ checkDerivative( phaseDensCopy.toSliceConst(), phaseDens.value.toSliceConst(), dPhaseDens[Deriv::dP].toSliceConst(),
+ dP, relTol, absTol, "phaseDens", "Pressure", phaseNames );
+ checkDerivative( phaseViscCopy.toSliceConst(), phaseVisc.value.toSliceConst(), dPhaseVisc[Deriv::dP].toSliceConst(),
+ dP, relTol, absTol, "phaseVisc", "Pressure", phaseNames );
+ } );
+ } // void testDerivatives
+
+
+protected:
+ static void writeTableToFile( string const & fileName, char const * content )
+ {
+ std::ofstream os( fileName );
+ ASSERT_TRUE( os.is_open() );
+ os << content;
+ os.close();
+ }
+
+ static void removeFile( string const & fileName )
+ {
+ int const ret = std::remove( fileName.c_str() );
+ ASSERT_TRUE( ret == 0 );
+ }
+
+
+private:
+ static TwoPhaseFluid * makeTwoPhaseFluid( string const & name, Group & parent );
+
+}; // class TwoPhaseFluidTest
+
+
+template<>
+TwoPhaseFluid * TwoPhaseFluidTest< true >::makeTwoPhaseFluid( string const & name, Group & parent )
+{
+ // 1D table with linear interpolation
+ localIndex constexpr Naxis = 6;
+ localIndex constexpr NaxisSingle = 1;
+
+ array1d< real64_array > densityCoordPhase0( 1 );
+ fill< Naxis >( densityCoordPhase0[0], { 0.22, 0.3, 0.5, 0.6, 0.8, 1.0 } );
+ real64_array densityValuesPhase0;
+ fill< Naxis >( densityValuesPhase0, { 0.00603, 0.04224, 0.04224, 0.22423, 0.31311, 0.40203 } );
+
+ array1d< real64_array > densityCoordPhase1( 1 );
+ fill< Naxis >( densityCoordPhase1[0], { 1.22, 1.3, 1.5, 1.6, 1.8, 2.0 } );
+ real64_array densityValuesPhase1;
+ fill< Naxis >( densityValuesPhase1, { 0.00603, 0.04224, 0.04224, 0.22423, 0.31311, 0.40203 } );
+
+
+ array1d< real64_array > viscosityCoordPhase0( 1 );
+ fill< Naxis >( viscosityCoordPhase0[0], { 0.22, 0.3, 0.5, 0.6, 0.8, 1.0 } );
+ real64_array viscosityValuesPhase0;
+ fill< Naxis >( viscosityValuesPhase0, { 40203, 31311, 22423, 15011, 4224, 603 } );
+
+ array1d< real64_array > viscosityCoordPhase1( 1 );
+ fill< NaxisSingle >( viscosityCoordPhase1[0], { 0.22 } );
+ real64_array viscosityValuesPhase1;
+ fill< NaxisSingle >( viscosityValuesPhase1, { 45 } );
+
+ initializeTable( "densityTablePhase0", densityCoordPhase0, densityValuesPhase0 );
+ initializeTable( "densityTablePhase1", densityCoordPhase1, densityValuesPhase1 );
+ initializeTable( "viscosityTablePhase0", viscosityCoordPhase0, viscosityValuesPhase0 );
+ initializeTable( "viscosityTablePhase1", viscosityCoordPhase1, viscosityValuesPhase1 );
+
+
+ // 2) Set up the constitutive model
+ TwoPhaseFluid & fluid = parent.registerGroup< TwoPhaseFluid >( name );
+
+ string_array & phaseNames = fluid.getReference< string_array >( TwoPhaseFluid::viewKeyStruct::phaseNamesString() );
+ phaseNames.emplace_back( "oil" );
+ phaseNames.emplace_back( "water" );
+
+ string_array & densityTableNames = fluid.getReference< string_array >( TwoPhaseFluid::viewKeyStruct::densityTableNamesString() );
+ densityTableNames.emplace_back( "densityTablePhase0" );
+ densityTableNames.emplace_back( "densityTablePhase1" );
+
+ string_array & viscosityTableNames = fluid.getReference< string_array >( TwoPhaseFluid::viewKeyStruct::viscosityTableNamesString() );
+ viscosityTableNames.emplace_back( "viscosityTablePhase0" );
+ viscosityTableNames.emplace_back( "viscosityTablePhase1" );
+
+ fluid.postInputInitializationRecursive();
+ return &fluid;
+}
+
+
+template<>
+TwoPhaseFluid * TwoPhaseFluidTest< false >::makeTwoPhaseFluid( string const & name, Group & parent )
+{
+ TwoPhaseFluid & fluid = parent.registerGroup< TwoPhaseFluid >( name );
+
+ path_array & tableNames = fluid.getReference< path_array >( TwoPhaseFluid::viewKeyStruct::tableFilesString() );
+ fill< 2 >( tableNames, {"phase0.txt", "phase1.txt"} );
+
+ fluid.postInputInitializationRecursive();
+ return &fluid;
+}
+
+
+
+using TwoPhaseFluidTestFromFiles = TwoPhaseFluidTest< false >;
+using TwoPhaseFluidTestFromTables = TwoPhaseFluidTest< true >;
+
+
+TEST_F( TwoPhaseFluidTestFromTables, testNumericalDerivative_initFromTables )
+{
+ auto & fluid = getFluid();
+ real64 const eps = std::sqrt( std::numeric_limits< real64 >::epsilon());
+ real64 constexpr relTol = 1.0e-8;
+ real64 constexpr absTol = 1.0e-8;
+
+ for( real64 const pressure : { 0.55, 1.0, 10.0 } )
+ {
+ testDerivatives( fluid, &getParent(), pressure, eps, relTol, absTol );
+ }
+}
+
+
+TEST_F( TwoPhaseFluidTestFromFiles, testNumericalDerivative_initFromFiles )
+{
+ auto & fluid = getFluid();
+ real64 const eps = std::sqrt( std::numeric_limits< real64 >::epsilon());
+ real64 constexpr relTol = 1.0e-8;
+ real64 constexpr absTol = 1.0e-8;
+
+ for( real64 const pressure : { 0.55, 1.0, 10.0 } )
+ {
+ testDerivatives( fluid, &getParent(), pressure, eps, relTol, absTol );
+ }
+}
+
+
+int main( int argc, char * * argv )
+{
+ ::testing::InitGoogleTest( &argc, argv );
+
+ conduit::Node conduitNode;
+ dataRepository::Group rootNode( "root", conduitNode );
+ FunctionManager functionManager( "FunctionManager", &rootNode );
+
+ int const result = RUN_ALL_TESTS();
+
+ return result;
+}
diff --git a/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverRunTest.hpp b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverRunTest.hpp
index eabe5616eee..750587bab88 100644
--- a/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverRunTest.hpp
+++ b/src/coreComponents/constitutiveDrivers/relativePermeability/RelpermDriverRunTest.hpp
@@ -19,7 +19,7 @@
#include "constitutiveDrivers/relativePermeability/RelpermDriver.hpp"
#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp"
#include "constitutive/relativePermeability/Layouts.hpp"
-#include "constitutive/relativePermeability/KilloughHysteresis.hpp"
+#include "constitutive/KilloughHysteresis.hpp"
namespace geos
@@ -96,10 +96,6 @@ RelpermDriver::runTest( RELPERM_TYPE & relperm,
arrayView2d< real64, compflow::USD_PHASE > phaseMaxHistoricalVolFraction = relperm.template getField< fields::relperm::phaseMaxHistoricalVolFraction >().reference();
arrayView2d< real64, compflow::USD_PHASE > phaseMinHistoricalVolFraction = relperm.template getField< fields::relperm::phaseMinHistoricalVolFraction >().reference();
-// arrayView1d< real64 > const drainagePhaseMinVolFraction = relperm.template getReference< array1d< real64 > >(
-// constitutive::TableRelativePermeabilityHysteresis::viewKeyStruct::drainagePhaseMinVolumeFractionString());
-// arrayView1d< real64 > const drainagePhaseMaxVolFraction = relperm.template getReference< array1d< real64 > >(
-// constitutive::TableRelativePermeabilityHysteresis::viewKeyStruct::drainagePhaseMaxVolumeFractionString());
constitutive::KilloughHysteresis::HysteresisCurve const wettingCurve = relperm.template getReference< constitutive::KilloughHysteresis::HysteresisCurve >(
constitutive::TableRelativePermeabilityHysteresis::viewKeyStruct::wettingCurveString());
@@ -109,14 +105,15 @@ RelpermDriver::runTest( RELPERM_TYPE & relperm,
{
if( phaseHasHysteresis[ipNonWetting] )
{
- phaseMaxHistoricalVolFraction[0][ipNonWetting] = nonWettingCurve.m_extremumPhaseVolFraction;
+ phaseMaxHistoricalVolFraction[0][ipNonWetting] = nonWettingCurve.oppositeBoundPhaseVolFraction;
GEOS_LOG( GEOS_FMT( "New max non-wetting phase historical phase volume fraction: {}", phaseMaxHistoricalVolFraction[0][ipNonWetting] ) );
}
if( phaseHasHysteresis[ipWetting] )
{
- phaseMinHistoricalVolFraction[0][ipWetting] = wettingCurve.m_extremumPhaseVolFraction;
+ phaseMinHistoricalVolFraction[0][ipWetting] = wettingCurve.oppositeBoundPhaseVolFraction;
GEOS_LOG( GEOS_FMT( "New min wetting phase historical phase volume fraction: {}", phaseMinHistoricalVolFraction[0][ipWetting] ) );
}
+
}
@@ -140,13 +137,12 @@ RelpermDriver::runTest( RELPERM_TYPE & relperm,
{
if( phaseHasHysteresis[ipNonWetting] )
{
-
- phaseMaxHistoricalVolFraction[0][ipNonWetting] = nonWettingCurve.m_criticalDrainagePhaseVolFraction;
+ phaseMaxHistoricalVolFraction[0][ipNonWetting] = nonWettingCurve.drainageExtremaPhaseVolFraction;
GEOS_LOG( GEOS_FMT( "New max non-wetting phase historical phase volume fraction: {}", phaseMaxHistoricalVolFraction[0][ipNonWetting] ) );
}
if( phaseHasHysteresis[ipWetting] )
{
- phaseMinHistoricalVolFraction[0][ipWetting] = wettingCurve.m_criticalDrainagePhaseVolFraction;
+ phaseMinHistoricalVolFraction[0][ipWetting] = wettingCurve.drainageExtremaPhaseVolFraction;
GEOS_LOG( GEOS_FMT( "New min wetting phase historical phase volume fraction: {}", phaseMinHistoricalVolFraction[0][ipWetting] ) );
}
}
diff --git a/src/coreComponents/finiteVolume/CellElementStencilTPFA.hpp b/src/coreComponents/finiteVolume/CellElementStencilTPFA.hpp
index 88fa3bb2b27..5c468d293cf 100644
--- a/src/coreComponents/finiteVolume/CellElementStencilTPFA.hpp
+++ b/src/coreComponents/finiteVolume/CellElementStencilTPFA.hpp
@@ -70,6 +70,20 @@ class CellElementStencilTPFAWrapper : public StencilWrapperBase< TwoPointStencil
CoefficientAccessor< arrayView3d< real64 const > > const & dCoeff_dVar,
real64 ( &weight )[1][2],
real64 ( &dWeight_dVar )[1][2] ) const;
+/**
+ * @brief Compute half weights and derivatives w.r.t to one variable.
+ * @param[in] iconn connection index
+ * @param[in] coefficient view accessor to the coefficient used to compute the weights
+ * @param[in] dCoeff_dVar view accessor to the derivative of the coefficient w.r.t to the variable
+ * @param[out] weight view weights
+ * @param[out] dWeight_dVar derivative of the weights w.r.t to the variable
+ */
+ GEOS_HOST_DEVICE
+ void computeHalfWeights( localIndex const iconn,
+ CoefficientAccessor< arrayView3d< real64 const > > const & coefficient,
+ CoefficientAccessor< arrayView3d< real64 const > > const & dCoeff_dVar,
+ real64 ( &weight )[1][2],
+ real64 ( &dWeight_dVar )[1][2] ) const;
/**
* @brief Compute weights and derivatives w.r.t to one variable without coefficient
@@ -293,6 +307,92 @@ CellElementStencilTPFAWrapper::
}
}
+GEOS_HOST_DEVICE
+inline void
+CellElementStencilTPFAWrapper::
+ computeHalfWeights( localIndex const iconn,
+ CoefficientAccessor< arrayView3d< real64 const > > const & coefficient,
+ CoefficientAccessor< arrayView3d< real64 const > > const & dCoeff_dVar,
+ real64 (& weight)[1][2],
+ real64 (& dWeight_dVar )[1][2] ) const
+{
+ real64 halfWeight[2];
+ real64 dHalfWeight_dVar[2];
+
+ // real64 const tolerance = 1e-30 * lengthTolerance; // TODO: choice of constant based on physics?
+
+ for( localIndex i = 0; i < 2; ++i )
+ {
+ localIndex const er = m_elementRegionIndices[iconn][i];
+ localIndex const esr = m_elementSubRegionIndices[iconn][i];
+ localIndex const ei = m_elementIndices[iconn][i];
+
+ halfWeight[i] = m_weights[iconn][i];
+ dHalfWeight_dVar[i] = m_weights[iconn][i];
+
+ // Proper computation
+ real64 faceNormal[3];
+ LvArray::tensorOps::copy< 3 >( faceNormal, m_faceNormal[iconn] );
+ if( LvArray::tensorOps::AiBi< 3 >( m_cellToFaceVec[iconn][i], faceNormal ) < 0.0 )
+ {
+ LvArray::tensorOps::scale< 3 >( faceNormal, -1 );
+ }
+
+ real64 faceConormal[3];
+ real64 dFaceConormal_dVar[3];
+ LvArray::tensorOps::hadamardProduct< 3 >( faceConormal, coefficient[er][esr][ei][0], faceNormal );
+ LvArray::tensorOps::hadamardProduct< 3 >( dFaceConormal_dVar, dCoeff_dVar[er][esr][ei][0], faceNormal );
+ halfWeight[i] *= LvArray::tensorOps::AiBi< 3 >( m_cellToFaceVec[iconn][i], faceConormal );
+ dHalfWeight_dVar[i] *= LvArray::tensorOps::AiBi< 3 >( m_cellToFaceVec[iconn][i], dFaceConormal_dVar );
+
+ // correct negative weight issue arising from non-K-orthogonal grids
+ // if( halfWeight[i] < 0.0 )
+ // {
+ // LvArray::tensorOps::hadamardProduct< 3 >( faceConormal,
+ // coefficient[er][esr][ei][0],
+ // m_cellToFaceVec[iconn][i] );
+ // LvArray::tensorOps::hadamardProduct< 3 >( dFaceConormal_dVar,
+ // dCoeff_dVar[er][esr][ei][0],
+ // m_cellToFaceVec[iconn][i] );
+ // halfWeight[i] = m_weights[iconn][i];
+ // dHalfWeight_dVar[i] = m_weights[iconn][i];
+ // halfWeight[i] *= LvArray::tensorOps::AiBi< 3 >( m_cellToFaceVec[iconn][i], faceConormal );
+ // dHalfWeight_dVar[i] *= LvArray::tensorOps::AiBi< 3 >( m_cellToFaceVec[iconn][i], dFaceConormal_dVar );
+ // }
+ }
+
+ // // Do harmonic and arithmetic averaging
+ // real64 const product = halfWeight[0]*halfWeight[1];
+ // real64 const sum = halfWeight[0]+halfWeight[1];
+
+ // real64 const harmonicWeight = sum > 0 ? product / sum : 0.0;
+ // real64 const arithmeticWeight = sum / 2;
+
+ // real64 dHarmonicWeight_dVar[2];
+ // real64 dArithmeticWeight_dVar[2];
+
+ // dHarmonicWeight_dVar[0] = sum > 0 ? (dHalfWeight_dVar[0]*sum*halfWeight[1] - dHalfWeight_dVar[0]*halfWeight[0]*halfWeight[1]) / (
+ // sum*sum ) : 0.0;
+ // dHarmonicWeight_dVar[1] = sum > 0 ? (dHalfWeight_dVar[1]*sum*halfWeight[0] - dHalfWeight_dVar[1]*halfWeight[1]*halfWeight[0]) / (
+ // sum*sum ) : 0.0;
+
+ // dArithmeticWeight_dVar[0] = dHalfWeight_dVar[0] / 2;
+ // dArithmeticWeight_dVar[1] = dHalfWeight_dVar[1] / 2;
+
+ // real64 const meanPermCoeff = 1.0; //TODO make it a member if it is really necessary
+
+ // real64 const value = meanPermCoeff * harmonicWeight + (1 - meanPermCoeff) * arithmeticWeight;
+ for( localIndex ke = 0; ke < 2; ++ke )
+ {
+ // weight[0][ke] = m_transMultiplier[iconn] * value * (ke == 0 ? 1 : -1);
+ weight[0][ke] = m_transMultiplier[iconn] * halfWeight[ke] * (ke == 0 ? 1 : -1);
+
+ // real64 const dValue_dVar = meanPermCoeff * dHarmonicWeight_dVar[ke] + (1 - meanPermCoeff) * dArithmeticWeight_dVar[ke];
+ // dWeight_dVar[0][ke] = m_transMultiplier[iconn] * dValue_dVar;
+ dWeight_dVar[0][ke] = m_transMultiplier[iconn] * dHalfWeight_dVar[ke];
+ }
+}
+
GEOS_HOST_DEVICE
inline void
CellElementStencilTPFAWrapper::
diff --git a/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.hpp b/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.hpp
index 7f9c1562366..4a191ca7614 100644
--- a/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.hpp
+++ b/src/coreComponents/finiteVolume/EmbeddedSurfaceToCellStencil.hpp
@@ -98,6 +98,22 @@ class EmbeddedSurfaceToCellStencilWrapper : public StencilWrapperBase< TwoPointS
real64 ( &weight )[1][2],
real64 ( &dWeight_dVar )[1][2] ) const;
+ /**
+ * @brief Compute half weigths and derivatives w.r.t to one variable.
+ * @param[in] iconn connection index
+ * @param[in] coefficient view accessor to the coefficient used to compute the weights
+ * @param[in] dCoeff_dVar view accessor to the derivative of the coefficient w.r.t to the variable
+ * @param[out] weight view weights
+ * @param[out] dWeight_dVar derivative of the weigths w.r.t to the variable
+ */
+
+ GEOS_HOST_DEVICE
+ void computeHalfWeights( localIndex const iconn,
+ CoefficientAccessor< arrayView3d< real64 const > > const & coefficient,
+ CoefficientAccessor< arrayView3d< real64 const > > const & dCoeff_dVar,
+ real64 ( &weight )[1][2],
+ real64 ( &dWeight_dVar )[1][2] ) const;
+
/**
* @brief Compute weigths and derivatives w.r.t to one variable without coefficient
* Used in ReactiveCompositionalMultiphaseOBL solver for thermal transmissibility computation:
@@ -243,6 +259,42 @@ EmbeddedSurfaceToCellStencilWrapper::
dWeight_dVar[0][1] = ( t0 * dt1 * sumOfTrans - dt1 * t0 * t1 ) / ( sumOfTrans * sumOfTrans );
}
+GEOS_HOST_DEVICE
+inline void
+EmbeddedSurfaceToCellStencilWrapper::
+ computeHalfWeights( localIndex iconn,
+ CoefficientAccessor< arrayView3d< real64 const > > const & coefficient,
+ CoefficientAccessor< arrayView3d< real64 const > > const & dCoeff_dVar,
+ real64 ( & weight )[1][2],
+ real64 ( & dWeight_dVar )[1][2] ) const
+{
+ localIndex const er0 = m_elementRegionIndices[iconn][0];
+ localIndex const esr0 = m_elementSubRegionIndices[iconn][0];
+ localIndex const ei0 = m_elementIndices[iconn][0];
+
+ localIndex const er1 = m_elementRegionIndices[iconn][1];
+ localIndex const esr1 = m_elementSubRegionIndices[iconn][1];
+ localIndex const ei1 = m_elementIndices[iconn][1];
+
+ // Will change when implementing collocation points. Will use fracture normal to project the permeability
+ real64 const t0 = m_weights[iconn][0] * LvArray::tensorOps::l2Norm< 3 >( coefficient[er0][esr0][ei0][0] );
+ // We consider the 3rd component of the permeability which is the normal one.
+ real64 const t1 = m_weights[iconn][1] * coefficient[er1][esr1][ei1][0][2];
+
+ real64 const sumOfTrans = t0+t1;
+ real64 const value = t0*t1/sumOfTrans;
+
+ weight[0][0] = value;
+ weight[0][1] = -value;
+
+ // We consider the 3rd component of the permeability which is the normal one.
+ real64 const dt0 = m_weights[iconn][0] * dCoeff_dVar[er0][esr0][ei0][0][0];
+ real64 const dt1 = m_weights[iconn][1] * dCoeff_dVar[er1][esr1][ei1][0][2];
+
+ dWeight_dVar[0][0] = ( dt0 * t1 * sumOfTrans - dt0 * t0 * t1 ) / ( sumOfTrans * sumOfTrans );
+ dWeight_dVar[0][1] = ( t0 * dt1 * sumOfTrans - dt1 * t0 * t1 ) / ( sumOfTrans * sumOfTrans );
+}
+
GEOS_HOST_DEVICE
inline void
EmbeddedSurfaceToCellStencilWrapper::
diff --git a/src/coreComponents/finiteVolume/FaceElementToCellStencil.hpp b/src/coreComponents/finiteVolume/FaceElementToCellStencil.hpp
index 6920e52b3bf..e86e6724bed 100644
--- a/src/coreComponents/finiteVolume/FaceElementToCellStencil.hpp
+++ b/src/coreComponents/finiteVolume/FaceElementToCellStencil.hpp
@@ -106,6 +106,21 @@ class FaceElementToCellStencilWrapper : public StencilWrapperBase< TwoPointStenc
real64 ( &weight )[1][2],
real64 ( &dWeight_dVar )[1][2] ) const;
+/**
+ * @brief Compute half weigths and derivatives w.r.t to one variable.
+ * @param[in] iconn connection index
+ * @param[in] coefficient view accessor to the coefficient used to compute the weights
+ * @param[in] dCoeff_dVar view accessor to the derivative of the coefficient w.r.t to the variable
+ * @param[out] weight view weights
+ * @param[out] dWeight_dVar derivative of the weigths w.r.t to the variable
+ */
+ GEOS_HOST_DEVICE
+ void computeHalfWeights( localIndex iconn,
+ CoefficientAccessor< arrayView3d< real64 const > > const & coefficient,
+ CoefficientAccessor< arrayView3d< real64 const > > const & dCoeff_dVar,
+ real64 ( &weight )[1][2],
+ real64 ( &dWeight_dVar )[1][2] ) const;
+
/**
* @brief Compute weigths and derivatives w.r.t to one variable without coefficient
* Used in ReactiveCompositionalMultiphaseOBL solver for thermal transmissibility computation:
@@ -297,6 +312,44 @@ inline void FaceElementToCellStencilWrapper::
dWeight_dVar[0][1] = m_transMultiplier[iconn] * ( t0 * dt1 * sumOfTrans - dt1 * t0 * t1 ) / ( sumOfTrans * sumOfTrans );
}
+GEOS_HOST_DEVICE
+inline void FaceElementToCellStencilWrapper::
+ computeHalfWeights( localIndex const iconn,
+ CoefficientAccessor< arrayView3d< real64 const > > const & coefficient,
+ CoefficientAccessor< arrayView3d< real64 const > > const & dCoeff_dVar,
+ real64 ( & weight )[1][2],
+ real64 ( & dWeight_dVar )[1][2] ) const
+{
+ localIndex const er0 = m_elementRegionIndices[iconn][0];
+ localIndex const esr0 = m_elementSubRegionIndices[iconn][0];
+ localIndex const ei0 = m_elementIndices[iconn][0];
+
+ localIndex const er1 = m_elementRegionIndices[iconn][1];
+ localIndex const esr1 = m_elementSubRegionIndices[iconn][1];
+ localIndex const ei1 = m_elementIndices[iconn][1];
+
+ real64 faceConormal[3];
+
+ // Will change when implementing collocation points.
+ LvArray::tensorOps::hadamardProduct< 3 >( faceConormal, coefficient[er0][esr0][ei0][0], m_faceNormal[iconn] );
+ real64 const t0 = m_weights[iconn][0] * LvArray::tensorOps::AiBi< 3 >( m_cellToFaceVec[iconn], faceConormal );
+ // We consider the 3rd component of the permeability which is the normal one.
+ real64 const t1 = m_weights[iconn][1] * coefficient[er1][esr1][ei1][0][2];
+
+ real64 const sumOfTrans = t0+t1;
+ real64 const value = m_transMultiplier[iconn]*t0*t1/sumOfTrans;
+
+ weight[0][0] = value;
+ weight[0][1] = -value;
+
+ // We consider the 3rd component of the permeability which is the normal one.
+ real64 const dt0 = m_weights[iconn][0] * dCoeff_dVar[er0][esr0][ei0][0][0];
+ real64 const dt1 = m_weights[iconn][1] * dCoeff_dVar[er1][esr1][ei1][0][2];
+
+ dWeight_dVar[0][0] = ( dt0 * t1 * sumOfTrans - dt0 * t0 * t1 ) / ( sumOfTrans * sumOfTrans );
+ dWeight_dVar[0][1] = ( t0 * dt1 * sumOfTrans - dt1 * t0 * t1 ) / ( sumOfTrans * sumOfTrans );
+}
+
GEOS_HOST_DEVICE
inline void
FaceElementToCellStencilWrapper
diff --git a/src/coreComponents/finiteVolume/SurfaceElementStencil.hpp b/src/coreComponents/finiteVolume/SurfaceElementStencil.hpp
index 5de67fe2f11..22942a1a648 100644
--- a/src/coreComponents/finiteVolume/SurfaceElementStencil.hpp
+++ b/src/coreComponents/finiteVolume/SurfaceElementStencil.hpp
@@ -110,6 +110,21 @@ class SurfaceElementStencilWrapper : public StencilWrapperBase< SurfaceElementSt
real64 ( &weight )[maxNumConnections][2],
real64 ( &dWeight_dVar )[maxNumConnections][2] ) const;
+ /**
+ * @brief Compute weights and derivatives w.r.t to one variable.
+ * @param[in] iconn connection index
+ * @param[in] coefficient view accessor to the coefficient used to compute the weights
+ * @param[in] dCoeff_dVar view accessor to the derivative of the coefficient w.r.t to the variable
+ * @param[out] weight view weights
+ * @param[out] dWeight_dVar derivative of the weights w.r.t to the variable
+ */
+ GEOS_HOST_DEVICE
+ void computeHalfWeights( localIndex iconn,
+ CoefficientAccessor< arrayView3d< real64 const > > const & coefficient,
+ CoefficientAccessor< arrayView3d< real64 const > > const & dCoeff_dVar,
+ real64 ( &weight )[maxNumConnections][2],
+ real64 ( &dWeight_dVar )[maxNumConnections][2] ) const;
+
/**
* @brief Compute weights and derivatives w.r.t to one variable without coefficient
* Used in ReactiveCompositionalMultiphaseOBL solver for thermal transmissibility computation:
@@ -364,6 +379,70 @@ SurfaceElementStencilWrapper::
}
}
+GEOS_HOST_DEVICE
+inline void
+SurfaceElementStencilWrapper::
+ computeHalfWeights( localIndex iconn,
+ CoefficientAccessor< arrayView3d< real64 const > > const & coefficient,
+ CoefficientAccessor< arrayView3d< real64 const > > const & dCoeff_dVar,
+ real64 ( & weight )[maxNumConnections][2],
+ real64 ( & dWeight_dVar )[maxNumConnections][2] ) const
+{
+
+ real64 sumOfTrans = 0.0;
+ for( localIndex k=0; k coordinates_dw;
// Swc = 0.22
// consistent with Swmaxd = 1-Sgcrd = 1-0 = 1
- geos::testing::fillArray( coordinates_dw,
- {.22, .25, .3, .35, .4, .45, .5, .55, .6, .65, .66, .68, .72, .82, .91, 1.} );
+ geosx::testing::fill_array( coordinates_dw, {.22, .25, .3, .35, .4, .45, .5, .55, .6, .65, .66, .68, .72, .82, .91, 1.} );
array1d< real64_array > coordinates_iw;
// Swc = 0.22
// consistent with Swmaxi = 1-Sgcri = 1-0.3 = 0.7
- geos::testing::fillArray( coordinates_iw, {.22, .25, .3, .35, .4, .45, .5, .55, .6, .65, .66, .7} );
+ geosx::testing::fill_array( coordinates_iw, {.22, .25, .3, .35, .4, .45, .5, .55, .6, .65, .66, .7} );
// Gas phase saturation, fifth column of Table 2
array1d< real64_array > coordinates_dg;
// Sgcrd = 0.0
// consistent with Swc = 0.22
- geos::testing::fillArray( coordinates_dg,
- {0.000, 0.010, 0.030, 0.050, 0.100, 0.150, 0.200, 0.250, 0.300, 0.350, 0.400, 0.450,
- 0.500,
- 0.550, 0.600, 0.650, 0.700, 0.750, 0.780} );
+ geosx::testing::fill_array( coordinates_dg,
+ {0.000, 0.010, 0.030, 0.050, 0.100, 0.150, 0.200, 0.250, 0.300, 0.350, 0.400, 0.450, 0.500,
+ 0.550, 0.600, 0.650, 0.700, 0.750, 0.780} );
array1d< real64_array > coordinates_ig;
// Sgcri = 0.30;
// consistent with Swc = 0.22
- geos::testing::fillArray( coordinates_ig,
- {0.300, 0.350, 0.400, 0.450, 0.500, 0.550, 0.600, 0.650, 0.700, 0.750, 0.78} );
+ geosx::testing::fill_array( coordinates_ig, {0.300, 0.350, 0.400, 0.450, 0.500, 0.550, 0.600, 0.650, 0.700, 0.750, 0.78} );
// then define the bounding drainage and imbibibition relative permeability
// Water phase drainage relperm
real64_array drainageValues_w;
- geos::testing::fillArray( drainageValues_w, {0.00000, 0.00100, 0.00300, 0.01000, 0.01800, 0.03500, 0.04000, 0.05700,
- 0.08800, 0.14500, 0.16000, 0.19000, 0.26300, 0.45500, 0.69200, 1.} );
+ geosx::testing::fill_array( drainageValues_w, {0.00000, 0.00100, 0.00300, 0.01000, 0.01800, 0.03500, 0.04000, 0.05700,
+ 0.08800, 0.14500, 0.16000, 0.19000, 0.26300, 0.45500, 0.69200, 1.} );
// Gas phase drainage relperm, seventh column of Table 2
real64_array drainageValues_g;
- geos::testing::fillArray( drainageValues_g, {0.00000, 0.00200, 0.00700, 0.01000, 0.02000, 0.04000, 0.07500,
- 0.12700, 0.18000, 0.24000, 0.31000, 0.37300, 0.46000, 0.55000,
- 0.64000, 0.73000, 0.82500, 0.92000, 1.00000} );
+ geosx::testing::fill_array( drainageValues_g, {0.00000, 0.00200, 0.00700, 0.01000, 0.02000, 0.04000, 0.07500,
+ 0.12700, 0.18000, 0.24000, 0.31000, 0.37300, 0.46000, 0.55000,
+ 0.64000, 0.73000, 0.82500, 0.92000, 1.00000} );
real64_array imbibitionValues_w;
- geos::testing::fillArray( imbibitionValues_w, {0, 0.0156, 0.0680, 0.1409, 0.2296, 0.3317, 0.4455, 0.5700,
- 0.7044, 0.8479, 0.8776, 0.9382} );
+ geosx::testing::fill_array( imbibitionValues_w, {0, 0.0156, 0.0680, 0.1409, 0.2296, 0.3317, 0.4455, 0.5700,
+ 0.7044, 0.8479, 0.8776, 0.9382} );
real64_array imbibitionValues_g;
- geos::testing::fillArray( imbibitionValues_g, {0.0000, 0.03361965, 0.09509072, 0.17469281, 0.26895718,
- 0.37587908, 0.49410588, 0.62264458, 0.76072577, 0.90773047, 1.} );
+ geosx::testing::fill_array( imbibitionValues_g, {0.0000, 0.03361965, 0.09509072, 0.17469281, 0.26895718,
+ 0.37587908, 0.49410588, 0.62264458, 0.76072577, 0.90773047, 1.} );
initializeTable( "drainageWater_swg",
coordinates_dw,
diff --git a/src/coreComponents/integrationTests/fluidFlowTests/CMakeLists.txt b/src/coreComponents/integrationTests/fluidFlowTests/CMakeLists.txt
index 951cac7c502..9a89d938e2e 100644
--- a/src/coreComponents/integrationTests/fluidFlowTests/CMakeLists.txt
+++ b/src/coreComponents/integrationTests/fluidFlowTests/CMakeLists.txt
@@ -4,6 +4,7 @@ set( gtest_geosx_tests
testThermalSinglePhaseFlow.cpp
testTransmissibility.cpp
testImmiscibleMultiphaseFlow.cpp
+ testImmiscibleInterfaceConditions.cpp
testSinglePhaseMFDPolyhedral.cpp
testSinglePhaseReactiveTransport.cpp )
diff --git a/src/coreComponents/integrationTests/fluidFlowTests/testImmiscibleInterfaceConditions.cpp b/src/coreComponents/integrationTests/fluidFlowTests/testImmiscibleInterfaceConditions.cpp
new file mode 100644
index 00000000000..ce90130a43c
--- /dev/null
+++ b/src/coreComponents/integrationTests/fluidFlowTests/testImmiscibleInterfaceConditions.cpp
@@ -0,0 +1,767 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+#define phase0MinSat1 0.0
+#define phase1MinSat1 0.0
+#define phase0MinSat2 0.0
+#define phase1MinSat2 0.0
+
+
+#include
+#include
+
+#include "mainInterface/initialization.hpp"
+#include "mainInterface/GeosxState.hpp"
+#include "constitutive/fluid/twophaseimmisciblefluid/TwoPhaseImmiscibleFluid.hpp"
+#include "physicsSolvers/PhysicsSolverManager.hpp"
+#include "physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlow.hpp"
+#include "integrationTests/fluidFlowTests/testCompFlowUtils.hpp"
+#include "constitutive/unitTests/FluidModelTest.hpp"
+#include "constitutive/unitTests/FluidModelTest_impl.hpp"
+#include "common/initializeEnvironment.hpp"
+#include "constitutive/relativePermeability/unitTests/constitutiveTestHelpers.hpp"
+#include "functions/FunctionManager.hpp"
+#include "constitutive/capillaryPressure/CapillaryPressureFields.hpp"
+
+#include
+
+
+
+using namespace geos;
+using namespace geos::dataRepository;
+using namespace geos::constitutive;
+using namespace geos::testing;
+
+CommandLineOptions g_commandLineOptions;
+
+TwoPhaseImmiscibleFluid * makeTwoPhaseImmiscibleFluid( TwoPhaseImmiscibleFluid & fluid )
+{
+
+ FunctionManager & functionManager = FunctionManager::getInstance();
+
+ // 1D table with linear interpolation
+// localIndex constexpr Naxis = 6;
+// localIndex constexpr NaxisSingle = 1;
+
+ real64_array densityCoordPhase0;
+ // fill( densityCoordPhase0, Feed< Naxis >{ 0.22, 0.3, 0.5, 0.6, 0.8, 1.0 } );
+ for( auto v : {0.0} )
+ densityCoordPhase0.emplace_back( v );
+ real64_array densityValuesPhase0;
+ // fill( densityValuesPhase0, Feed< Naxis >{ 0.00603, 0.04224, 0.04224, 0.22423, 0.31311, 0.40203 } );
+ for( auto v : {1000.0} )
+ densityValuesPhase0.emplace_back( v );
+
+ real64_array densityCoordPhase1;
+ // fill( densityCoordPhase1, Feed< Naxis >{ 1.22, 1.3, 1.5, 1.6, 1.8, 2.0 } );
+ for( auto v : {0.0} )
+ densityCoordPhase1.emplace_back( v );
+ real64_array densityValuesPhase1;
+ // fill( densityValuesPhase1, Feed< Naxis >{ 0.00603, 0.04224, 0.04224, 0.22423, 0.31311, 0.40203 } );
+ for( auto v : {100.0} )
+ densityValuesPhase1.emplace_back( v );
+
+ real64_array viscosityCoordPhase0;
+ // fill( viscosityCoordPhase0, Feed< Naxis >{ 0.22, 0.3, 0.5, 0.6, 0.8, 1.0 } );
+ for( auto v : {0.0} )
+ viscosityCoordPhase0.emplace_back( v );
+ real64_array viscosityValuesPhase0;
+ // fill( viscosityValuesPhase0, Feed< Naxis >{ 40203, 31311, 22423, 15011, 4224, 603 } );
+ for( auto v : {0.001} )
+ viscosityValuesPhase0.emplace_back( v );
+
+ real64_array viscosityCoordPhase1;
+ // fill( viscosityCoordPhase1, Feed< NaxisSingle >{ 0.22 } );
+ for( auto v : {0.0} )
+ viscosityCoordPhase1.emplace_back( v );
+
+ real64_array viscosityValuesPhase1;
+ // fill( viscosityValuesPhase1, Feed< NaxisSingle >{ 45 } );
+ for( auto v : {0.001} )
+ viscosityValuesPhase1.emplace_back( v );
+
+ TableFunction & table_density0 = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "densityTablePhase0" ) );
+ array1d< real64_array > coords_density0;
+ coords_density0.emplace_back( densityCoordPhase0 );
+ table_density0.setTableCoordinates( coords_density0, { units::Dimensionless } );
+ table_density0.setTableValues( densityValuesPhase0, units::Dimensionless );
+ table_density0.reInitializeFunction();
+
+ table_density0.setInterpolationMethod( TableFunction::InterpolationType::Linear );
+
+ TableFunction & table_density1 = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "densityTablePhase1" ) );
+ array1d< real64_array > coords_density1;
+ coords_density1.emplace_back( densityCoordPhase1 );
+ table_density1.setTableCoordinates( coords_density1, { units::Dimensionless } );
+ table_density1.setTableValues( densityValuesPhase1, units::Dimensionless );
+ table_density1.reInitializeFunction();
+
+ table_density1.setInterpolationMethod( TableFunction::InterpolationType::Linear );
+
+ TableFunction & table_viscosity0 = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "viscosityTablePhase0" ) );
+ array1d< real64_array > coords_viscosity0;
+ coords_viscosity0.emplace_back( viscosityCoordPhase0 );
+ table_viscosity0.setTableCoordinates( coords_viscosity0, { units::Dimensionless } );
+ table_viscosity0.setTableValues( viscosityValuesPhase0, units::Dimensionless );
+ table_viscosity0.reInitializeFunction();
+
+ table_viscosity0.setInterpolationMethod( TableFunction::InterpolationType::Linear );
+
+ TableFunction & table_viscosity1 = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "viscosityTablePhase1" ) );
+ array1d< real64_array > coords_viscosity1;
+ coords_viscosity1.emplace_back( viscosityCoordPhase1 );
+ table_viscosity1.setTableCoordinates( coords_viscosity1, { units::Dimensionless } );
+ table_viscosity1.setTableValues( viscosityValuesPhase1, units::Dimensionless );
+ table_viscosity1.reInitializeFunction();
+
+ table_viscosity1.setInterpolationMethod( TableFunction::InterpolationType::Linear );
+
+
+ // createTable( "densityTablePhase0", densityCoordPhase0, densityValuesPhase0 );
+ // createTable( "densityTablePhase1", densityCoordPhase1, densityValuesPhase1 );
+ // createTable( "viscosityTablePhase0", viscosityCoordPhase0, viscosityValuesPhase0 );
+ // createTable( "viscosityTablePhase1", viscosityCoordPhase1, viscosityValuesPhase1 );
+
+ // 2) Set up the constitutive model
+
+ string_array & phaseNames = fluid.getReference< string_array >( TwoPhaseImmiscibleFluid::viewKeyStruct::phaseNamesString() );
+ phaseNames.emplace_back( "water" );
+ phaseNames.emplace_back( "gas" );
+
+ string_array & densityTableNames = fluid.getReference< string_array >( TwoPhaseImmiscibleFluid::viewKeyStruct::densityTableNamesString() );
+ densityTableNames.emplace_back( "densityTablePhase0" );
+ densityTableNames.emplace_back( "densityTablePhase1" );
+
+ string_array & viscosityTableNames = fluid.getReference< string_array >( TwoPhaseImmiscibleFluid::viewKeyStruct::viscosityTableNamesString() );
+ viscosityTableNames.emplace_back( "viscosityTablePhase0" );
+ viscosityTableNames.emplace_back( "viscosityTablePhase1" );
+
+ fluid.postInputInitializationRecursive();
+ fluid.initialize(); // to test all the checks
+
+ return &fluid;
+}
+
+CapillaryPressureBase & makeJFunctionCapPressureTwoPhase( string const & name, Group & parent )
+{
+ FunctionManager & functionManager = FunctionManager::getInstance();
+
+ // 1) First, define the tables
+
+ // // 1D table, various interpolation methods
+ // localIndex const Naxis = 12;
+
+ // // Setup table
+ // array1d< real64_array > coordinates;
+ // coordinates.resize( 1 );
+ // coordinates[0].resize( Naxis );
+
+ // coordinates[0][0] = 0.0;
+ // coordinates[0][1] = 0.05;
+ // coordinates[0][2] = 0.15;
+ // coordinates[0][3] = 0.25;
+ // coordinates[0][4] = 0.35;
+ // coordinates[0][5] = 0.45;
+ // coordinates[0][6] = 0.55;
+ // coordinates[0][7] = 0.65;
+ // coordinates[0][8] = 0.75;
+ // coordinates[0][9] = 0.85;
+ // coordinates[0][10] = 0.95;
+ // coordinates[0][11] = 1.0;
+
+ // real64_array values( Naxis );
+ // values[0] = 4.331729359;
+ // values[1] = 3.523266264;
+ // values[2] = 2.677103439;
+ // values[3] = 2.356150157;
+ // values[4] = 2.166062360;
+ // values[5] = 2.034158727;
+ // values[6] = 1.934627222;
+ // values[7] = 1.855494313;
+ // values[8] = 1.790286970;
+ // values[9] = 1.735134860;
+ // values[10] = 1.687551617;
+ // values[11] = 1.666049754;
+
+
+ localIndex const Naxis = 2;
+
+ // Setup table
+ array1d< real64_array > coordinates;
+ coordinates.resize( 1 );
+ coordinates[0].resize( Naxis );
+
+ coordinates[0][0] = 0.0;
+ coordinates[0][1] = 1.0;
+
+ real64_array values( Naxis );
+ values[0] = 4.331729359;
+ values[1] = 1.666049754;
+
+
+ TableFunction & table_w = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "water_jFunction" ) );
+ table_w.setTableCoordinates( coordinates, { units::Dimensionless } );
+ table_w.setTableValues( values, units::Dimensionless );
+ table_w.reInitializeFunction();
+
+ table_w.setInterpolationMethod( TableFunction::InterpolationType::Linear );
+
+ // 2) Then set up the constitutive model
+
+ JFunctionCapillaryPressure & capPressure = parent.registerGroup< JFunctionCapillaryPressure >( name );
+
+ string_array & phaseNames = capPressure.getReference< string_array >( CapillaryPressureBase::viewKeyStruct::phaseNamesString() );
+ phaseNames.resize( 2 );
+ phaseNames[0] = "water"; phaseNames[1] = "gas";
+
+ auto & waterTableName = capPressure.getReference< string >( JFunctionCapillaryPressure::viewKeyStruct::wettingNonWettingJFuncTableNameString() );
+ waterTableName = "water_jFunction";
+
+ auto & surfaceTension = capPressure.getReference< real64 >( JFunctionCapillaryPressure::viewKeyStruct::wettingNonWettingSurfaceTensionString() );
+ //surfaceTension = 23.86955676433857e-3;
+ surfaceTension = 0.02;
+
+ auto & permeabilityDirection =
+ capPressure.getReference< JFunctionCapillaryPressure::PermeabilityDirection >( JFunctionCapillaryPressure::viewKeyStruct::permeabilityDirectionString() );
+ permeabilityDirection = JFunctionCapillaryPressure::PermeabilityDirection::XY;
+
+ capPressure.postInputInitializationRecursive();
+ capPressure.initialize(); // to test all the checks
+
+ return capPressure;
+}
+
+CapillaryPressureBase & makeTableCapPressureTwoPhase1( string const & name, Group & parent )
+{
+ FunctionManager & functionManager = FunctionManager::getInstance();
+
+ // 1) First, define the tables
+
+ // 1D table, various interpolation methods
+ localIndex Naxis = 12;
+
+ // Setup table
+ array1d< real64_array > coordinates;
+ coordinates.resize( 1 );
+ coordinates[0].resize( Naxis );
+ coordinates[0][0] = 0.0;
+ coordinates[0][1] = 0.05;
+ coordinates[0][2] = 0.15;
+ coordinates[0][3] = 0.25;
+ coordinates[0][4] = 0.35;
+ coordinates[0][5] = 0.45;
+ coordinates[0][6] = 0.55;
+ coordinates[0][7] = 0.65;
+ coordinates[0][8] = 0.75;
+ coordinates[0][9] = 0.85;
+ coordinates[0][10] = 0.95;
+ coordinates[0][11] = 1.0;
+
+ real64_array values( Naxis );
+ values[0] = 130000.0;
+ values[1] = 90572.79;
+ values[2] = 49307.11;
+ values[3] = 33654.85;
+ values[4] = 24384.64;
+ values[5] = 17951.96;
+ values[6] = 13098;
+ values[7] = 9238.84;
+ values[8] = 6058.81;
+ values[9] = 3369.14;
+ values[10] = 1048.6;
+ values[11] = 0.0;
+
+ // localIndex const Naxis = 2;
+
+ // // Setup table
+ // array1d< real64_array > coordinates;
+ // coordinates.resize( 1 );
+ // coordinates[0].resize( Naxis );
+
+ // coordinates[0][0] = 0.0;
+ // coordinates[0][1] = 1.0;
+
+ // real64_array values( Naxis );
+ // values[0] = 129999.999994362;
+ // values[1] = 50000.0000139914;
+
+
+ TableFunction & table_w = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "water_pc" ) );
+ table_w.setTableCoordinates( coordinates, { units::Dimensionless } );
+ table_w.setTableValues( values, units::Pressure );
+ table_w.reInitializeFunction();
+
+ table_w.setInterpolationMethod( TableFunction::InterpolationType::Linear );
+
+ // 2) Then set up the constitutive model
+
+ TableCapillaryPressure & capPressure = parent.registerGroup< TableCapillaryPressure >( name );
+
+ string_array & phaseNames = capPressure.getReference< string_array >( CapillaryPressureBase::viewKeyStruct::phaseNamesString() );
+ phaseNames.resize( 2 );
+ phaseNames[0] = "water"; phaseNames[1] = "gas";
+
+ auto & waterTableName = capPressure.getReference< string >( TableCapillaryPressure::viewKeyStruct::wettingNonWettingCapPresTableNameString() );
+ waterTableName = "water_pc";
+
+ capPressure.postInputInitializationRecursive();
+ capPressure.initialize(); // to test all the checks
+ return capPressure;
+}
+
+CapillaryPressureBase & makeTableCapPressureTwoPhase2( string const & name, Group & parent )
+{
+ FunctionManager & functionManager = FunctionManager::getInstance();
+
+ // 1) First, define the tables
+
+ // 1D table, various interpolation methods
+ localIndex Naxis = 12;
+
+ // Setup table
+ array1d< real64_array > coordinates;
+ coordinates.resize( 1 );
+ coordinates[0].resize( Naxis );
+ coordinates[0][0] = 0.0;
+ coordinates[0][1] = 0.05;
+ coordinates[0][2] = 0.15;
+ coordinates[0][3] = 0.25;
+ coordinates[0][4] = 0.35;
+ coordinates[0][5] = 0.45;
+ coordinates[0][6] = 0.55;
+ coordinates[0][7] = 0.65;
+ coordinates[0][8] = 0.75;
+ coordinates[0][9] = 0.85;
+ coordinates[0][10] = 0.95;
+ coordinates[0][11] = 1.0;
+
+ real64_array values( Naxis );
+ values[0] = 195000.0;
+ values[1] = 135859.25;
+ values[2] = 73960.67;
+ values[3] = 50482.28;
+ values[4] = 36576.96;
+ values[5] = 26927.94;
+ values[6] = 19647;
+ values[7] = 13858.26;
+ values[8] = 9088.2;
+ values[9] = 5053.72;
+ values[10] = 1572.9;
+ values[11] = 0.0;
+
+ // localIndex const Naxis = 2;
+
+ // // Setup table
+ // array1d< real64_array > coordinates;
+ // coordinates.resize( 1 );
+ // coordinates[0].resize( Naxis );
+
+ // coordinates[0][0] = 0.0;
+ // coordinates[0][1] = 1.0;
+
+ // real64_array values( Naxis );
+ // values[0] = 129999.999994362;
+ // values[1] = 50000.0000139914;
+
+
+ TableFunction & table_w = dynamicCast< TableFunction & >( *functionManager.createChild( "TableFunction", "water_pc" ) );
+ table_w.setTableCoordinates( coordinates, { units::Dimensionless } );
+ table_w.setTableValues( values, units::Pressure );
+ table_w.reInitializeFunction();
+
+ table_w.setInterpolationMethod( TableFunction::InterpolationType::Linear );
+
+ // 2) Then set up the constitutive model
+
+ TableCapillaryPressure & capPressure = parent.registerGroup< TableCapillaryPressure >( name );
+
+ string_array & phaseNames = capPressure.getReference< string_array >( CapillaryPressureBase::viewKeyStruct::phaseNamesString() );
+ phaseNames.resize( 2 );
+ phaseNames[0] = "water"; phaseNames[1] = "gas";
+
+ auto & waterTableName = capPressure.getReference< string >( TableCapillaryPressure::viewKeyStruct::wettingNonWettingCapPresTableNameString() );
+ waterTableName = "water_pc";
+
+ capPressure.postInputInitializationRecursive();
+ capPressure.initialize(); // to test all the checks
+ return capPressure;
+}
+
+CapillaryPressureBase & makeBrooksCoreyCapPressureTwoPhase1( string const & name, Group & parent )
+{
+ BrooksCoreyCapillaryPressure & capPressure = parent.registerGroup< BrooksCoreyCapillaryPressure >( name );
+
+ string_array & phaseNames = capPressure.getReference< string_array >( CapillaryPressureBase::viewKeyStruct::phaseNamesString() );
+ phaseNames.resize( 2 );
+ phaseNames[0] = "water"; phaseNames[1] = "gas";
+
+ array1d< real64 > & phaseMinSat = capPressure.getReference< array1d< real64 > >( BrooksCoreyCapillaryPressure::viewKeyStruct::phaseMinVolumeFractionString() );
+ phaseMinSat.resize( 2 );
+ phaseMinSat[0] = phase0MinSat1; phaseMinSat[1] = phase1MinSat1;
+
+ array1d< real64 > & phaseCapPressureExpInv =
+ capPressure.getReference< array1d< real64 > >( BrooksCoreyCapillaryPressure::viewKeyStruct::phaseCapPressureExponentInvString() );
+ phaseCapPressureExpInv.resize( 2 );
+ phaseCapPressureExpInv[0] = 4; phaseCapPressureExpInv[1] = 1;
+
+ array1d< real64 > & phaseEntryPressure = capPressure.getReference< array1d< real64 > >( BrooksCoreyCapillaryPressure::viewKeyStruct::phaseEntryPressureString() );
+ phaseEntryPressure.resize( 2 );
+ phaseEntryPressure[0] = 4.0e3; phaseEntryPressure[1] = 0;
+
+ real64 & capPressureEpsilon = capPressure.getReference< real64 >( BrooksCoreyCapillaryPressure::viewKeyStruct::capPressureEpsilonString() );
+ capPressureEpsilon = 1.0e-8;
+
+ capPressure.postInputInitializationRecursive();
+ return capPressure;
+}
+
+CapillaryPressureBase & makeBrooksCoreyCapPressureTwoPhase2( string const & name, Group & parent )
+{
+ BrooksCoreyCapillaryPressure & capPressure = parent.registerGroup< BrooksCoreyCapillaryPressure >( name );
+
+ string_array & phaseNames = capPressure.getReference< string_array >( CapillaryPressureBase::viewKeyStruct::phaseNamesString() );
+ phaseNames.resize( 2 );
+ phaseNames[0] = "water"; phaseNames[1] = "gas";
+
+ array1d< real64 > & phaseMinSat = capPressure.getReference< array1d< real64 > >( BrooksCoreyCapillaryPressure::viewKeyStruct::phaseMinVolumeFractionString() );
+ phaseMinSat.resize( 2 );
+ phaseMinSat[0] = phase0MinSat2; phaseMinSat[1] = phase1MinSat2;
+
+ array1d< real64 > & phaseCapPressureExpInv =
+ capPressure.getReference< array1d< real64 > >( BrooksCoreyCapillaryPressure::viewKeyStruct::phaseCapPressureExponentInvString() );
+ phaseCapPressureExpInv.resize( 2 );
+ phaseCapPressureExpInv[0] = 4; phaseCapPressureExpInv[1] = 1;
+
+ array1d< real64 > & phaseEntryPressure = capPressure.getReference< array1d< real64 > >( BrooksCoreyCapillaryPressure::viewKeyStruct::phaseEntryPressureString() );
+ phaseEntryPressure.resize( 2 );
+ phaseEntryPressure[0] = 2.0e3; phaseEntryPressure[1] = 0;
+
+ real64 & capPressureEpsilon = capPressure.getReference< real64 >( BrooksCoreyCapillaryPressure::viewKeyStruct::capPressureEpsilonString() );
+ capPressureEpsilon = 1e-8;
+
+ capPressure.postInputInitializationRecursive();
+ return capPressure;
+}
+
+RelativePermeabilityBase & makeBrooksCoreyRelPerm( string const & name, Group & parent )
+{
+ BrooksCoreyRelativePermeability & relPerm = parent.registerGroup< BrooksCoreyRelativePermeability >( name );
+
+ string_array & phaseNames = relPerm.getReference< string_array >( RelativePermeabilityBase::viewKeyStruct::phaseNamesString() );
+ phaseNames.resize( 2 );
+ phaseNames[0] = "water"; phaseNames[1] = "gas";
+
+ array1d< real64 > & phaseMinSat = relPerm.getReference< array1d< real64 > >( BrooksCoreyRelativePermeability::viewKeyStruct::phaseMinVolumeFractionString() );
+ phaseMinSat.resize( 2 );
+ phaseMinSat[0] = phase0MinSat1; phaseMinSat[1] = phase1MinSat1;
+
+ array1d< real64 > & phaseRelPermExp = relPerm.getReference< array1d< real64 > >( BrooksCoreyRelativePermeability::viewKeyStruct::phaseRelPermExponentString() );
+ phaseRelPermExp.resize( 2 );
+ phaseRelPermExp[0] = 2.0; phaseRelPermExp[1] = 2.0;
+
+ array1d< real64 > & phaseRelPermMaxVal = relPerm.getReference< array1d< real64 > >( BrooksCoreyRelativePermeability::viewKeyStruct::phaseRelPermMaxValueString() );
+ phaseRelPermMaxVal.resize( 2 );
+ phaseRelPermMaxVal[0] = 1.0; phaseRelPermMaxVal[1] = 1.0;
+
+ relPerm.postInputInitializationRecursive();
+ return relPerm;
+}
+
+class ImmiscibleInterfaceConditionsTest : public FluidModelTest< TwoPhaseImmiscibleFluid, 2 >
+{
+public:
+ ImmiscibleInterfaceConditionsTest(): state( std::make_unique< CommandLineOptions >( g_commandLineOptions )),
+ m_parent( "TestParentGroup", m_node )
+
+ {}
+
+protected:
+
+ static real64 constexpr time = 0.0;
+ static real64 constexpr dt = 1e4;
+ static real64 constexpr eps = std::numeric_limits< real64 >::epsilon();
+
+ GeosxState state;
+ ImmiscibleMultiphaseFlow *solver;
+ conduit::Node m_node;
+ dataRepository::Group m_parent;
+};
+
+real64 constexpr ImmiscibleInterfaceConditionsTest::time;
+real64 constexpr ImmiscibleInterfaceConditionsTest::dt;
+real64 constexpr ImmiscibleInterfaceConditionsTest::eps;
+
+
+
+TEST_F( ImmiscibleInterfaceConditionsTest, LocalNonlinearSolverConvergence )
+{
+
+ // using Base = FluidModelTest< TwoPhaseImmiscibleFluid, 2 >;
+ createFluid( "fluid", [this]( TwoPhaseImmiscibleFluid & fluid ){
+ makeTwoPhaseImmiscibleFluid( fluid );
+
+ // getting constitutive models:
+ RelativePermeabilityBase & relPerm = makeBrooksCoreyRelPerm( "relPerm", this->m_parent );
+ RelativePermeabilityBase * relPermPtr = &relPerm;
+ // CapillaryPressureBase & capPressure0 = makeJFunctionCapPressureTwoPhase( "capPressure0", this->m_parent );
+ // CapillaryPressureBase * capPressurePtr0 = &capPressure0;
+
+ CapillaryPressureBase & capPressure0 = makeTableCapPressureTwoPhase1( "capPressure0", this->m_parent );
+ CapillaryPressureBase * capPressurePtr0 = &capPressure0;
+
+ CapillaryPressureBase & capPressure1 = makeTableCapPressureTwoPhase2( "capPressure1", this->m_parent );
+ CapillaryPressureBase * capPressurePtr1 = &capPressure1;
+ // CapillaryPressureBase & capPressure0 = makeBrooksCoreyCapPressureTwoPhase1( "capPressure0", this->m_parent );
+ // CapillaryPressureBase * capPressurePtr0 = &capPressure0;
+
+ // CapillaryPressureBase & capPressure1 = makeBrooksCoreyCapPressureTwoPhase2( "capPressure1", this->m_parent );
+ // CapillaryPressureBase * capPressurePtr1 = &capPressure1;
+
+ std::vector< RelativePermeabilityBase * > relPerms = {relPermPtr, relPermPtr};
+ std::vector< CapillaryPressureBase * > capPressures = {capPressurePtr0, capPressurePtr1};
+ std::vector< TwoPhaseImmiscibleFluid * > fluids = { &fluid, &fluid };
+ // real64 uT = 3.2864545889999906e-05;
+
+ real64 uT = 3.3e-2;
+// real64 uT = 1e-7;
+ stdVector< real64 > saturations = {0.2, 0.4};
+ stdVector< real64 > trappedSats1 = {phase0MinSat1, phase1MinSat1};
+ stdVector< real64 > trappedSats2 = {phase0MinSat2, phase1MinSat2};
+ stdVector< real64 > pressures = {1e7, 1e7};
+ stdVector< real64 > JFMultipliers = {45016.662822296035, 30011.108548197357};
+ stdVector< fields::cappres::ModeIndexType > modes = {static_cast< fields::cappres::ModeIndexType >(0), static_cast< fields::cappres::ModeIndexType >(0)};
+ stdVector< real64 > transHats = {1.9738466000000002e-12, 4.4411548500000007e-12};
+ stdVector< real64 > dTransHats_dP = {0.0, 0.0};
+ stdVector< real64 > gravCoefHats = {490.5, 490.5};
+ stdVector< real64 > gravCoefs = {465.97500000000002, 515.02499999999998};
+ stdVector< real64 > cellCenterDuT = {0.0, 0.0, 0.0, 0.0}; // duT_dP[0], duT_dP[1], duT_dS[0], duT_dS[1]
+ stdVector< real64 > cellCenterDens = {1000.0, 800.0}; // density for each phase
+ stdVector< real64 > cellCenterDens_dP = {0.0, 0.0, 0.0, 0.0}; // dDens_dP[0][0], dDens_dP[0][1], dDens_dP[1][0], dDens_dP[1][1]
+ stdVector< real64 > phaseMaxHistVolFrac1 = {0.0, 0.0};
+ stdVector< real64 > phaseMinHistVolFrac1 = {0.0, 0.0};
+ stdVector< real64 > phaseMaxHistVolFrac2 = {0.0, 0.0};
+ stdVector< real64 > phaseMinHistVolFrac2 = {0.0, 0.0};
+
+ stdVector< real64 > phi = {0.0, 0.0};
+ stdVector< real64 > grad_phi_P = {0.0, 0.0, 0.0, 0.0};
+ stdVector< real64 > grad_phi_S = {0.0, 0.0, 0.0, 0.0};
+ bool converged = false;
+
+
+ std::ofstream outFile( "local_solver_results.csv" );
+
+
+ // Write data to the file
+ outFile << "Si";
+ outFile << ",";
+ outFile << "Sj";
+ outFile << ",";
+ outFile << "Fw_alpha";
+ outFile << ",";
+ outFile << "Fn_alpha";
+ outFile << ",";
+ outFile << "Residual_initial";
+ outFile << ",";
+ outFile << "Pc_int";
+ outFile << ",";
+ outFile << "Residual";
+ outFile << ",";
+ outFile << "newton";
+ outFile << std::endl;
+
+ real64 const start_sat = 0.0;
+ real64 const end_sat = 1.0;
+ real64 const dS = 1e-2;
+ // real64 Si = 0.0;
+ // real64 Sj = 0.9;
+ real64 warmStartPc = 1000;
+
+ for( real64 Si = start_sat; Si <= end_sat + 1e-8; Si += dS )
+ {
+ for( real64 Sj = start_sat; Sj <= end_sat + 1e-8; Sj += dS )
+ {
+ saturations[0] = Si;
+ saturations[1] = Sj;
+
+ auto t0 = std::chrono::high_resolution_clock::now();
+
+// Call the GEOS local solver
+ geos::immiscibleMultiphaseKernels::local_solver( uT, saturations, pressures, JFMultipliers, trappedSats1, trappedSats2, modes, transHats, dTransHats_dP, gravCoefHats, gravCoefs,
+ cellCenterDuT, cellCenterDens, cellCenterDens_dP, relPerms, capPressures, fluids, phi, grad_phi_P, grad_phi_S, converged,
+ phaseMaxHistVolFrac1, phaseMinHistVolFrac1, phaseMaxHistVolFrac2, phaseMinHistVolFrac2, warmStartPc );
+
+
+
+ auto t1 = std::chrono::high_resolution_clock::now();
+ std::chrono::duration< double > elapsed = t1 - t0;
+// std::cout << "Local solver time: " << elapsed.count() << " s" << std::endl;
+ EXPECT_TRUE( converged ) << "Local solver diverged for saturations Si=" << Si << ", Sj=" << Sj;
+
+ // Write data to the file
+ outFile << GEOS_FMT( "{:10.10e}", saturations[0] );
+ outFile << GEOS_FMT( ",{:10.10e}", saturations[1] );
+ outFile << GEOS_FMT( ",{:10.10e}", phi[0] );
+ outFile << GEOS_FMT( ",{:10.10e}", phi[1] );
+ outFile << GEOS_FMT( ",{:10.10e}", grad_phi_P[0] );
+ outFile << GEOS_FMT( ",{:10.10e}", grad_phi_P[1] );
+ outFile << GEOS_FMT( ",{:10.10e}", grad_phi_P[2] );
+ outFile << GEOS_FMT( ",{:10.10e}", grad_phi_P[3] );
+ outFile << std::endl;
+ phi[0] = 0;
+ phi[1] = 0;
+ grad_phi_P[0] = 0;
+ grad_phi_P[1] = 0;
+ grad_phi_P[2] = 0;
+ grad_phi_P[3] = 0;
+ grad_phi_S[0] = 0;
+ grad_phi_S[1] = 0;
+ grad_phi_S[2] = 0;
+ grad_phi_S[3] = 0;
+
+ }
+ }
+
+ outFile.close();
+
+ } );
+}
+
+TEST_F( ImmiscibleInterfaceConditionsTest, LocalSolverResults )
+{
+
+ // using Base = FluidModelTest< TwoPhaseImmiscibleFluid, 2 >;
+ createFluid( "fluid", [this]( TwoPhaseImmiscibleFluid & fluid ){
+ makeTwoPhaseImmiscibleFluid( fluid );
+
+ // getting constitutive models:
+ RelativePermeabilityBase & relPerm = makeBrooksCoreyRelPerm( "relPerm", this->m_parent );
+ RelativePermeabilityBase * relPermPtr = &relPerm;
+
+ CapillaryPressureBase & capPressure0 = makeBrooksCoreyCapPressureTwoPhase1( "capPressure0", this->m_parent );
+ CapillaryPressureBase * capPressurePtr0 = &capPressure0;
+
+ CapillaryPressureBase & capPressure1 = makeBrooksCoreyCapPressureTwoPhase2( "capPressure1", this->m_parent );
+ CapillaryPressureBase * capPressurePtr1 = &capPressure1;
+
+ std::vector< RelativePermeabilityBase * > relPerms = {relPermPtr, relPermPtr};
+ std::vector< CapillaryPressureBase * > capPressures = {capPressurePtr0, capPressurePtr1};
+ std::vector< TwoPhaseImmiscibleFluid * > fluids = { &fluid, &fluid };
+
+ real64 uT = 0.000001889581158;
+
+ stdVector< real64 > saturations = {0.6, 0.3};
+ stdVector< real64 > trappedSats1 = {phase0MinSat1, phase1MinSat1};
+ stdVector< real64 > trappedSats2 = {phase0MinSat2, phase1MinSat2};
+ stdVector< real64 > pressures = {1e7, 1e7};
+ stdVector< real64 > JFMultipliers = {45016.662822296035, 30011.108548197357};
+ stdVector< fields::cappres::ModeIndexType > modes = {static_cast< fields::cappres::ModeIndexType >(0), static_cast< fields::cappres::ModeIndexType >(0)};
+ stdVector< real64 > transHats = {2.0e-12, 8.0e-12};
+ stdVector< real64 > dTransHats_dP = {0.0, 0.0};
+ stdVector< real64 > gravCoefHats = {49.05, 49.05};
+ stdVector< real64 > gravCoefs = {46.5975, 51.5025};
+ stdVector< real64 > cellCenterDuT = {8.32E-10, -8.32E-10, 0.0000063429744518, -0.0000012971521486}; // duT_dP[0], duT_dP[1], duT_dS[0],
+ // duT_dS[1]
+ stdVector< real64 > cellCenterDens = {1000.0, 100.0}; // density for each phase
+ stdVector< real64 > cellCenterDens_dP = {0.0, 0.0, 0.0, 0.0}; // dDens_dP[0][0], dDens_dP[0][1], dDens_dP[1][0], dDens_dP[1][1]
+ stdVector< real64 > phaseMaxHistVolFrac1 = {0.0, 0.0};
+ stdVector< real64 > phaseMinHistVolFrac1 = {0.0, 0.0};
+ stdVector< real64 > phaseMaxHistVolFrac2 = {0.0, 0.0};
+ stdVector< real64 > phaseMinHistVolFrac2 = {0.0, 0.0};
+
+ stdVector< real64 > phi = {0.0, 0.0};
+ stdVector< real64 > grad_phi_P = {0.0, 0.0, 0.0, 0.0};
+ stdVector< real64 > grad_phi_S = {0.0, 0.0, 0.0, 0.0};
+ bool converged = false;
+ real64 warmStartPc = 1000;
+// Call the GEOS local solver
+ geos::immiscibleMultiphaseKernels::local_solver( uT, saturations, pressures, JFMultipliers, trappedSats1, trappedSats2, modes, transHats, dTransHats_dP, gravCoefHats, gravCoefs,
+ cellCenterDuT, cellCenterDens, cellCenterDens_dP, relPerms, capPressures, fluids, phi, grad_phi_P, grad_phi_S, converged,
+ phaseMaxHistVolFrac1, phaseMinHistVolFrac1, phaseMaxHistVolFrac2, phaseMinHistVolFrac2,
+ warmStartPc );
+
+ real64 const tolerance_eps = std::sqrt( std::numeric_limits< real64 >::epsilon() );
+ real64 const tol = 1e-4;
+ real64 const abs_tolerance = tolerance_eps * tol;
+
+ EXPECT_NEAR( phi[0], 1.676451024635667e-03, abs_tolerance );
+ EXPECT_NEAR( phi[1], 2.131301333609180e-05, abs_tolerance );
+ EXPECT_NEAR( grad_phi_P[0], 5.760000000000000e-07, abs_tolerance );
+ EXPECT_NEAR( grad_phi_P[1], -5.760000000000000e-07, abs_tolerance );
+ EXPECT_NEAR( grad_phi_P[2], 2.560000000000001e-08, abs_tolerance );
+ EXPECT_NEAR( grad_phi_P[3], -2.560000000000001e-08, abs_tolerance );
+ EXPECT_NEAR( grad_phi_S[0], 7.268012258072125e-03, abs_tolerance );
+ EXPECT_NEAR( grad_phi_S[1], -8.980284105794445e-04, abs_tolerance );
+ EXPECT_NEAR( grad_phi_S[2], -9.250378062747074e-05, abs_tolerance );
+ EXPECT_NEAR( grad_phi_S[3], -3.991237380353088e-05, abs_tolerance );
+
+
+ } );
+}
+
+
+int main( int argc, char * *argv )
+{
+ ::testing::InitGoogleTest( &argc, argv );
+ g_commandLineOptions = *geos::basicSetup( argc, argv );
+ int const result = RUN_ALL_TESTS();
+ geos::basicCleanup();
+ return result;
+}
+
+// maybe needed later on
+// TEST_F( CapillaryPressureTest, numericalDerivatives_jFunctionCapPressureTwoPhase )
+// {
+// initialize( makeJFunctionCapPressureTwoPhase( "capPressure", m_parent ) );
+
+// // here, we have to apply a special treatment to this test
+// // to make sure that the J-function multiplier is initialized using initializeRockState
+// // this requires calling allocateConstitutiveData in advance (it will be called again later, in the "test" function)
+
+// // setup some values for porosity and permeability
+// array2d< real64 > porosity;
+// porosity.resize( 1, 1 );
+// porosity[0][0] = 0.13496794266569806;
+// array3d< real64 > permeability;
+// permeability.resize( 1, 1, 3 );
+// permeability[0][0][0] = 0.1722194e-15;
+// permeability[0][0][1] = 0.3423156e-15;
+// permeability[0][0][2] = 0.2324191e-15;
+
+// // initialize the J-function multiplier (done on GPU if GPU is available)
+// m_model->allocateConstitutiveData( m_parent, 1 );
+// m_model->initializeRockState( porosity.toViewConst(), permeability.toViewConst() );
+
+// // move the multiplier back to the CPU since the test is performed on the CPU
+// auto & jFuncMultiplier =
+// m_model->getReference< array2d< real64 > >( fields::cappres::jFuncMultiplier::key() );
+// jFuncMultiplier.move( hostMemorySpace, false );
+
+// // we are ready to proceed to the test
+
+// real64 const eps = std::sqrt( std::numeric_limits< real64 >::epsilon() );
+// real64 const tol = 1e-4;
+
+// real64 const start_sat = 0.3;
+// real64 const end_sat = 0.9;
+// real64 const dS = 1e-1;
+// array1d< real64 > sat( 2 );
+// sat[0] = start_sat; sat[1] = 1-sat[0];
+// while( sat[0] <= end_sat )
+// {
+// test( sat, eps, tol );
+// sat[0] += dS;
+// sat[1] = 1 - sat[0];
+// }
+
+// }
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
index 1f6bd171acc..d42ae52f6a4 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
+++ b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
@@ -29,8 +29,6 @@ set( fluidFlowSolvers_headers
ImmiscibleMultiphaseFlow.hpp
ImmiscibleMultiphaseFlowFields.hpp
LogLevelsInfo.hpp
- ReactiveCompositionalMultiphaseOBL.hpp
- ReactiveCompositionalMultiphaseOBLFields.hpp
SourceFluxStatistics.hpp
SinglePhaseBase.hpp
SinglePhaseBaseFields.hpp
@@ -67,18 +65,6 @@ set( fluidFlowSolvers_headers
kernels/singlePhase/ThermalFluxComputeKernel.hpp
kernels/singlePhase/proppant/ProppantBaseKernels.hpp
kernels/singlePhase/proppant/ProppantFluxKernels.hpp
- kernels/singlePhase/reactive/AccumulationKernels.hpp
- kernels/singlePhase/reactive/DirichletFluxComputeKernel.hpp
- kernels/singlePhase/reactive/FluidUpdateKernel.hpp
- kernels/singlePhase/reactive/FluxComputeKernel.hpp
- kernels/singlePhase/reactive/KernelLaunchSelectors.hpp
- kernels/singlePhase/reactive/ReactionUpdateKernel.hpp
- kernels/singlePhase/reactive/ResidualNormKernel.hpp
- kernels/singlePhase/reactive/SourceFluxComputeKernel.hpp
- kernels/singlePhase/reactive/ThermalAccumulationKernels.hpp
- kernels/singlePhase/reactive/ThermalDirichletFluxComputeKernel.hpp
- kernels/singlePhase/reactive/ThermalFluxComputeKernel.hpp
- kernels/singlePhase/reactive/ThermalSourceFluxComputeKernel.hpp
kernels/compositional/AccumulationKernel.hpp
kernels/compositional/AquiferBCKernel.hpp
kernels/compositional/PPUPhaseFlux.hpp
@@ -106,7 +92,6 @@ set( fluidFlowSolvers_headers
kernels/compositional/PotGrad.hpp
kernels/compositional/PPUPhaseFlux.hpp
kernels/compositional/PropertyKernelBase.hpp
- kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp
kernels/compositional/RelativePermeabilityUpdateKernel.hpp
kernels/compositional/ResidualNormKernel.hpp
kernels/compositional/SolidInternalEnergyUpdateKernel.hpp
@@ -147,14 +132,12 @@ set( fluidFlowSolvers_sources
CompositionalMultiphaseStatistics.cpp
CompositionalMultiphaseHybridFVM.cpp
ImmiscibleMultiphaseFlow.cpp
- ReactiveCompositionalMultiphaseOBL.cpp
FlowSolverBase.cpp
SinglePhaseBase.cpp
SinglePhaseStatistics.cpp
SinglePhaseFVM.cpp
SinglePhaseHybridFVM.cpp
SinglePhaseProppantBase.cpp
- SinglePhaseReactiveTransport.cpp
SourceFluxStatistics.cpp
SolutionCheckHelpers.cpp
StencilDataCollection.cpp
@@ -177,8 +160,10 @@ file( READ "${CMAKE_CURRENT_LIST_DIR}/kernelSpecs.json" kernelSpecs )
set( kernelTemplateFileList "" )
# Keep only the templates that are unrelated to hybrid flux/dirichlet
+if( ENABLE_HPCREACT AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../constitutive/HPCReact/CMakeLists.txt" )
list( APPEND kernelTemplateFileList
ReactiveCompositionalMultiphaseOBLKernels.cpp.template )
+endif()
foreach( kernelTemplateFile ${kernelTemplateFileList} )
get_filename_component( jsonKey ${kernelTemplateFile} NAME_WE )
@@ -191,6 +176,31 @@ foreach( kernelTemplateFile ${kernelTemplateFileList} )
list(APPEND fluidFlowSolvers_sources ${sourceFiles})
endforeach()
+# Conditionally add reactive transport files when HPCReact is available
+if( ENABLE_HPCREACT AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../constitutive/HPCReact/CMakeLists.txt" )
+ list( APPEND fluidFlowSolvers_headers
+ ReactiveCompositionalMultiphaseOBL.hpp
+ ReactiveCompositionalMultiphaseOBLFields.hpp
+ kernels/singlePhase/reactive/AccumulationKernels.hpp
+ kernels/singlePhase/reactive/DirichletFluxComputeKernel.hpp
+ kernels/singlePhase/reactive/FluidUpdateKernel.hpp
+ kernels/singlePhase/reactive/FluxComputeKernel.hpp
+ kernels/singlePhase/reactive/KernelLaunchSelectors.hpp
+ kernels/singlePhase/reactive/ReactionUpdateKernel.hpp
+ kernels/singlePhase/reactive/ResidualNormKernel.hpp
+ kernels/singlePhase/reactive/SourceFluxComputeKernel.hpp
+ kernels/singlePhase/reactive/ThermalAccumulationKernels.hpp
+ kernels/singlePhase/reactive/ThermalDirichletFluxComputeKernel.hpp
+ kernels/singlePhase/reactive/ThermalFluxComputeKernel.hpp
+ kernels/singlePhase/reactive/ThermalSourceFluxComputeKernel.hpp
+ kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp
+ SinglePhaseReactiveTransport.hpp )
+
+ list( APPEND fluidFlowSolvers_sources
+ ReactiveCompositionalMultiphaseOBL.cpp
+ SinglePhaseReactiveTransport.cpp )
+endif()
+
# TODO: The two kernels below have non-matching file names and JSON keys.
# Either fix them to follow pattern, or come up with another mechanism.
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp
index 8d0900adf38..f3e0154034b 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp
@@ -1002,12 +1002,24 @@ void CompositionalMultiphaseBase::initializeFluidState( MeshLevel & mesh,
// We postpone the other constitutive models for now
// Now, we initialize and update each constitutive model one by one
-
// initialized phase volume fraction
arrayView2d< real64 const, compflow::USD_PHASE > const phaseVolFrac =
- subRegion.template getField< flow::phaseVolumeFraction >();
+ subRegion.template getField< fields::flow::phaseVolumeFraction >();
- // Initialize/update the relative permeability model using the initial phase volume fraction
+ // 4.2 Save the computed porosity into the old porosity
+ //
+ // Note:
+ // - This must be called after updatePorosityAndPermeability
+ // - This step depends on porosity
+ string const & solidName = subRegion.template getReference< string >( viewKeyStruct::solidNamesString() );
+ CoupledSolidBase const & porousMaterial = getConstitutiveModel< CoupledSolidBase >( subRegion, solidName );
+ porousMaterial.initializeState();
+
+ // 4.3 Initialize/update the relative permeability model using the initial phase volume fraction
+ // This is needed to handle relative permeability hysteresis
+ // Also, initialize the fluid model (to compute the initial total mass density, needed to compute the body force increment in
+ // coupled simulations)
+ //
// Note:
// - This must be called after updatePhaseVolumeFraction
// - This step depends on phaseVolFraction
@@ -2868,6 +2880,7 @@ void CompositionalMultiphaseBase::implicitStepComplete( real64 const & time,
CapillaryPressureBase const & capPressureMaterial =
getConstitutiveModel< CapillaryPressureBase >( subRegion, capPressName );
capPressureMaterial.saveConvergedRockState( porosity, permeability );
+ capPressureMaterial.saveConvergedPhaseVolFractionState( phaseVolFrac );
}
// Step 6: if the thermal option is on, send the converged porosity and phase volume fraction to the thermal conductivity model
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp
index 227055bf3ed..a03fbf63a99 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp
@@ -20,6 +20,11 @@
#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASEBASE_HPP_
#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASEBASE_HPP_
+#include "common/DataLayouts.hpp"
+#include "constitutive/fluid/multifluid/Layouts.hpp"
+#include "constitutive/relativePermeability/Layouts.hpp"
+#include "constitutive/capillaryPressure/Layouts.hpp"
+#include "fieldSpecification/FieldSpecificationManager.hpp"
#include "physicsSolvers/fluidFlow/FlowSolverBase.hpp"
#include "common/DataLayouts.hpp"
#include "constitutive/fluid/multifluid/Layouts.hpp"
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlow.cpp b/src/coreComponents/physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlow.cpp
index 6bd4ead9e6b..d22d18ae8fc 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlow.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlow.cpp
@@ -17,31 +17,34 @@
* @file ImmiscibleMultiphaseFlow.cpp
*/
-#include "ImmiscibleMultiphaseFlow.hpp"
-
-#include "FlowSolverBaseFields.hpp"
-#include "physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlowFields.hpp"
-#include "physicsSolvers/PhysicsSolverBaseKernels.hpp"
-#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp"
-#include "physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/ImmiscibleMultiphaseKernels.hpp"
-#include "physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp"
-#include "physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp"
-#include "constitutive/capillaryPressure/CapillaryPressureSelector.hpp"
-#include "constitutive/relativePermeability/RelativePermeabilitySelector.hpp"
-
-#include "fieldSpecification/EquilibriumInitialCondition.hpp"
-#include "fieldSpecification/SourceFluxBoundaryCondition.hpp"
-#include "physicsSolvers/fluidFlow/SourceFluxStatistics.hpp"
-#include "physicsSolvers/LogLevelsInfo.hpp"
-
-#include "constitutive/ConstitutivePassThru.hpp"
-#include "constitutive/fluid/twophaseimmisciblefluid/TwoPhaseImmiscibleFluid.hpp"
-
-#include
-
-#if defined( __INTEL_COMPILER )
-#pragma GCC optimize "O0"
-#endif
+ #include "ImmiscibleMultiphaseFlow.hpp"
+
+ #include "FlowSolverBaseFields.hpp"
+ #include "physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlowFields.hpp"
+ #include "physicsSolvers/PhysicsSolverBaseKernels.hpp"
+ #include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp"
+ #include "physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/ImmiscibleMultiphaseKernels.hpp"
+ #include "physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/CapillaryPressureUpdateKernel.hpp"
+ #include "physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp"
+ #include "physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp"
+ #include "constitutive/ConstitutiveManager.hpp"
+ #include "constitutive/capillaryPressure/CapillaryPressureFields.hpp"
+ #include "constitutive/capillaryPressure/CapillaryPressureSelector.hpp"
+ #include "constitutive/relativePermeability/RelativePermeabilitySelector.hpp"
+
+ #include "fieldSpecification/EquilibriumInitialCondition.hpp"
+ #include "fieldSpecification/SourceFluxBoundaryCondition.hpp"
+ #include "physicsSolvers/fluidFlow/SourceFluxStatistics.hpp"
+ #include "physicsSolvers/LogLevelsInfo.hpp"
+
+ #include "constitutive/ConstitutivePassThru.hpp"
+ #include "constitutive/fluid/twophaseimmisciblefluid/TwoPhaseImmiscibleFluid.hpp"
+
+ #include
+
+ #if defined( __INTEL_COMPILER )
+ #pragma GCC optimize "O0"
+ #endif
namespace geos
{
@@ -90,7 +93,12 @@ ImmiscibleMultiphaseFlow::ImmiscibleMultiphaseFlow( const string & name,
setSizedFromParent( 0 ).
setInputFlag( InputFlags::OPTIONAL ).
setApplyDefaultValue( 0.2 ).
- setDescription( "Target (absolute) change in the phase volume fraction within a single time step." );
+ setDescription( "Target (absolute) change in phase volume fraction in a time step" );
+
+ this->registerWrapper( viewKeyStruct::interfaceFaceSetNamesString(),
+ &m_interfaceFaceSetNames ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Names of the interface face sets" );
}
void ImmiscibleMultiphaseFlow::postInputInitialization()
@@ -143,9 +151,9 @@ void ImmiscibleMultiphaseFlow::registerDataOnMesh( Group & meshBodies )
string & capPresName = subRegion.getReference< string >( viewKeyStruct::capPressureNamesString() );
capPresName = getConstitutiveName< CapillaryPressureBase >( subRegion );
GEOS_THROW_IF( capPresName.empty(),
- GEOS_FMT( "Capillary pressure model not found on subregion {}",
- subRegion.getName() ),
- InputError, getDataContext(), subRegion.getDataContext() );
+ GEOS_FMT( "{}: Capillary pressure model not found on subregion {}",
+ getDataContext(), subRegion.getDataContext() ),
+ InputError );
}
// The resizing of the arrays needs to happen here, before the call to initializePreSubGroups,
@@ -169,7 +177,7 @@ void ImmiscibleMultiphaseFlow::registerDataOnMesh( Group & meshBodies )
reference().resizeDimension< 1 >( m_numPhases );
subRegion.registerField< dPhaseMobility >( getName() ).
- reference().resizeDimension< 1, 2 >( m_numPhases, m_numPhases ); // dP, dS
+ reference().resizeDimension< 1, 2 >( m_numPhases, m_numPhases ); // dP, dS
} );
@@ -203,6 +211,194 @@ void ImmiscibleMultiphaseFlow::initializePreSubGroups()
temp.setValues< parallelHostPolicy >( m_inputTemperature );
} );
} );
+
+ // ***** Create FaceElements *****
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & meshLevel,
+ string_array const & GEOS_UNUSED_PARAM( regionNames ))
+ {
+
+ FaceManager const & faceManager = meshLevel.getFaceManager();
+ Group const & faceSetGroup = faceManager.sets();
+ ElementRegionManager & elemManager = meshLevel.getElemManager();
+ m_interfaceConstitutivePairs.resize( m_interfaceFaceSetNames.size() );
+ m_interfacePairRegionIndices.resize( m_interfaceFaceSetNames.size() );
+ // Explicitly initialize all tuple entries to nullptr so that ranks without
+ // interface face elements don't leave garbage pointers in the tuples
+ for( size_t i = 0; i < m_interfaceConstitutivePairs.size(); ++i )
+ {
+ m_interfaceConstitutivePairs[i][0] = std::make_tuple( nullptr, nullptr, nullptr );
+ m_interfaceConstitutivePairs[i][1] = std::make_tuple( nullptr, nullptr, nullptr );
+ m_interfacePairRegionIndices[i] = {{ -1, -1 }};
+ }
+
+ // this is the FaceElement Level
+ for( size_t surfaceRegionIndex=0; surfaceRegionIndex < m_interfaceFaceSetNames.size(); ++surfaceRegionIndex )
+ {
+ string const & faceSetName = m_interfaceFaceSetNames[surfaceRegionIndex];
+ SortedArrayView< localIndex const > const & faceSet = faceSetGroup.getReference< SortedArray< localIndex > >( faceSetName );
+ SurfaceElementRegion & faceRegion = elemManager.getRegion< SurfaceElementRegion >( faceSetName );
+
+ for( localIndex const faceIndex : faceSet )
+ {
+ localIndex const faceIndices[2] = { faceIndex, faceIndex };
+ faceRegion.addToSurfaceMesh( &faceManager, faceIndices );
+ }
+
+ FaceElementSubRegion const & faceSubRegion = faceRegion.getUniqueSubRegion< FaceElementSubRegion >();
+ FixedToManyElementRelation const & faceElementsToCells = faceSubRegion.getToCellRelation();
+
+ // Precompute numRegions once (it's constant for all face elements)
+ localIndex const numRegions = elemManager.numRegions();
+ constexpr int MAX_REASONABLE_REGION_INDEX = 100000;
+
+ std::function< std::tuple< CellElementSubRegion *, CellElementSubRegion * >(localIndex) > getSubregions = [&]( localIndex surfaceSubRegionIndex ) -> std::tuple< CellElementSubRegion *,
+ CellElementSubRegion * >
+ {
+
+ int regionIdx0 = faceElementsToCells.m_toElementRegion[surfaceSubRegionIndex][0];
+ int regionIdx1 = faceElementsToCells.m_toElementRegion[surfaceSubRegionIndex][1];
+ int subRegionIdx0 = faceElementsToCells.m_toElementSubRegion[surfaceSubRegionIndex][0];
+ int subRegionIdx1 = faceElementsToCells.m_toElementSubRegion[surfaceSubRegionIndex][1];
+
+ // Fast validation checks (ordered from cheapest to most expensive)
+ if( regionIdx0 < 0 || regionIdx1 < 0 ||
+ subRegionIdx0 < 0 || subRegionIdx1 < 0 )
+ {
+ return std::make_tuple( nullptr, nullptr );
+ }
+
+ if( regionIdx0 > MAX_REASONABLE_REGION_INDEX || regionIdx1 > MAX_REASONABLE_REGION_INDEX )
+ {
+ return std::make_tuple( nullptr, nullptr );
+ }
+
+ if( static_cast< localIndex >( regionIdx0 ) >= numRegions ||
+ static_cast< localIndex >( regionIdx1 ) >= numRegions )
+ {
+ return std::make_tuple( nullptr, nullptr );
+ }
+
+ // Try to get regions - they might not exist on this MPI rank even if index is in range
+ ElementRegionBase * region0BasePtr = nullptr;
+ ElementRegionBase * region1BasePtr = nullptr;
+
+ try
+ {
+ region0BasePtr = &elemManager.getRegion< ElementRegionBase >( regionIdx0 );
+ region1BasePtr = &elemManager.getRegion< ElementRegionBase >( regionIdx1 );
+ }
+ catch( std::exception const & )
+ {
+ return std::make_tuple( nullptr, nullptr );
+ }
+
+ // Check if they are CellElementRegion (interface conditions only apply to cell-to-cell interfaces)
+ CellElementRegion * cellRegion0 = dynamic_cast< CellElementRegion * >( region0BasePtr );
+ CellElementRegion * cellRegion1 = dynamic_cast< CellElementRegion * >( region1BasePtr );
+
+ if( cellRegion0 == nullptr || cellRegion1 == nullptr )
+ {
+ return std::make_tuple( nullptr, nullptr );
+ }
+
+ // Validate subregion indices before accessing
+ if( static_cast< localIndex >( subRegionIdx0 ) >= cellRegion0->numSubRegions() ||
+ static_cast< localIndex >( subRegionIdx1 ) >= cellRegion1->numSubRegions() )
+ {
+ return std::make_tuple( nullptr, nullptr );
+ }
+
+ CellElementSubRegion * subRegion0 = &cellRegion0->getSubRegion< CellElementSubRegion >( subRegionIdx0 );
+ CellElementSubRegion * subRegion1 = &cellRegion1->getSubRegion< CellElementSubRegion >( subRegionIdx1 );
+ return std::make_tuple( subRegion0, subRegion1 );
+ };
+
+ // std::tuple< CellElementSubRegion *, CellElementSubRegion * > subRegionPair = getSubregions( surfaceRegionIndex );
+ // CellElementSubRegion * subRegion0 = std::get< 0 >( subRegionPair );
+ // CellElementSubRegion * subRegion1 = std::get< 1 >( subRegionPair );
+
+ // // get constitutives by type and name: relPerms, capPressures, Fluids (three pointers)
+ // std::string & relPermName0 = subRegion0->getReference< std::string >( viewKeyStruct::relPermNamesString());
+ // std::string & relPermName1 = subRegion1->getReference< std::string >( viewKeyStruct::relPermNamesString());
+ // RelativePermeabilityBase * relPerm0 = &getConstitutiveModel< RelativePermeabilityBase >( *subRegion0, relPermName0 );
+ // RelativePermeabilityBase * relPerm1 = &getConstitutiveModel< RelativePermeabilityBase >( *subRegion1, relPermName1 );
+
+ // std::string & cappresName0 = subRegion0->getReference< std::string >( viewKeyStruct::capPressureNamesString());
+ // std::string & cappresName1 = subRegion1->getReference< std::string >( viewKeyStruct::capPressureNamesString());
+ // CapillaryPressureBase * capPressure0 = &getConstitutiveModel< CapillaryPressureBase >( *subRegion0, cappresName0 );
+ // CapillaryPressureBase * capPressure1 = &getConstitutiveModel< CapillaryPressureBase >( *subRegion1, cappresName1 );
+
+ // std::string & fluidName0 = subRegion0->getReference< std::string >( viewKeyStruct::fluidNamesString() );
+ // std::string & fluidName1 = subRegion1->getReference< std::string >( viewKeyStruct::fluidNamesString() );
+
+ // TwoPhaseImmiscibleFluid * fluid0 = &getConstitutiveModel< TwoPhaseImmiscibleFluid >( *subRegion0, fluidName0 );
+ // TwoPhaseImmiscibleFluid * fluid1 = &getConstitutiveModel< TwoPhaseImmiscibleFluid >( *subRegion1, fluidName1 );
+
+ // m_interfaceConstitutivePairs[surfaceRegionIndex][0] = std::make_tuple( relPerm0, capPressure0, fluid0 );
+ // m_interfaceConstitutivePairs[surfaceRegionIndex][1] = std::make_tuple( relPerm1, capPressure1, fluid1 );
+ // Find a representative face element that connects two CellElementRegion objects
+// (not SurfaceElementRegion, which we don't handle for interface conditions)
+ CellElementSubRegion * subRegion0 = nullptr;
+ CellElementSubRegion * subRegion1 = nullptr;
+ bool foundValidFei = false;
+ localIndex pairRegionIdx0 = -1;
+ localIndex pairRegionIdx1 = -1;
+
+// Single loop to find a valid face element (avoids redundant scanning)
+ for( localIndex i = 0; i < faceElementsToCells.size(); ++i )
+ {
+ // Quick check: must have two adjacent cells with non-negative region indices
+ if( faceElementsToCells.m_toElementRegion[i].size() >= 2 &&
+ faceElementsToCells.m_toElementRegion[i][0] >= 0 &&
+ faceElementsToCells.m_toElementRegion[i][1] >= 0 )
+ {
+ std::tuple< CellElementSubRegion *, CellElementSubRegion * > subRegionPair = getSubregions( i );
+ CellElementSubRegion * testSubRegion0 = std::get< 0 >( subRegionPair );
+ CellElementSubRegion * testSubRegion1 = std::get< 1 >( subRegionPair );
+
+ if( testSubRegion0 != nullptr && testSubRegion1 != nullptr )
+ {
+ subRegion0 = testSubRegion0;
+ subRegion1 = testSubRegion1;
+ pairRegionIdx0 = faceElementsToCells.m_toElementRegion[i][0];
+ pairRegionIdx1 = faceElementsToCells.m_toElementRegion[i][1];
+ foundValidFei = true;
+ break;
+ }
+ }
+ }
+
+// If no valid face element connecting two CellElementRegion objects, skip this surface region
+ if( !foundValidFei )
+ {
+ continue;
+ }
+
+// get constitutives by type and name: relPerms, capPressures, Fluids (three pointers)
+ std::string & relPermName0 = subRegion0->getReference< std::string >( viewKeyStruct::relPermNamesString());
+ std::string & relPermName1 = subRegion1->getReference< std::string >( viewKeyStruct::relPermNamesString());
+ RelativePermeabilityBase * relPerm0 = &getConstitutiveModel< RelativePermeabilityBase >( *subRegion0, relPermName0 );
+ RelativePermeabilityBase * relPerm1 = &getConstitutiveModel< RelativePermeabilityBase >( *subRegion1, relPermName1 );
+
+ std::string & cappresName0 = subRegion0->getReference< std::string >( viewKeyStruct::capPressureNamesString());
+ std::string & cappresName1 = subRegion1->getReference< std::string >( viewKeyStruct::capPressureNamesString());
+ CapillaryPressureBase * capPressure0 = &getConstitutiveModel< CapillaryPressureBase >( *subRegion0, cappresName0 );
+ CapillaryPressureBase * capPressure1 = &getConstitutiveModel< CapillaryPressureBase >( *subRegion1, cappresName1 );
+
+ std::string & fluidName0 = subRegion0->getReference< std::string >( viewKeyStruct::fluidNamesString() );
+ std::string & fluidName1 = subRegion1->getReference< std::string >( viewKeyStruct::fluidNamesString() );
+
+ TwoPhaseImmiscibleFluid * fluid0 = &getConstitutiveModel< TwoPhaseImmiscibleFluid >( *subRegion0, fluidName0 );
+ TwoPhaseImmiscibleFluid * fluid1 = &getConstitutiveModel< TwoPhaseImmiscibleFluid >( *subRegion1, fluidName1 );
+
+ m_interfaceConstitutivePairs[surfaceRegionIndex][0] = std::make_tuple( relPerm0, capPressure0, fluid0 );
+ m_interfaceConstitutivePairs[surfaceRegionIndex][1] = std::make_tuple( relPerm1, capPressure1, fluid1 );
+ m_interfacePairRegionIndices[surfaceRegionIndex] = {{ pairRegionIdx0, pairRegionIdx1 }};
+
+ }
+ } );
+
}
@@ -265,7 +461,8 @@ void ImmiscibleMultiphaseFlow::updateCapPressureModel( ObjectManagerBase & dataG
{
typename TYPEOFREF( castedCapPres ) ::KernelWrapper capPresWrapper = castedCapPres.createKernelWrapper();
- isothermalCompositionalMultiphaseBaseKernels::
+ // isothermalCompositionalMultiphaseBaseKernels::
+ immiscibleMultiphaseKernels::
CapillaryPressureUpdateKernel::
launch< parallelDevicePolicy<> >( dataGroup.size(),
capPresWrapper,
@@ -373,7 +570,7 @@ void ImmiscibleMultiphaseFlow::initializeFluidState( MeshLevel & mesh,
getConstitutiveModel< PermeabilityBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::permeabilityNamesString() ) );
permeabilityModel.scaleHorizontalPermeability( netToGross );
porousSolid.scaleReferencePorosity( netToGross );
- saveConvergedState( subRegion ); // necessary for a meaningful porosity update in sequential schemes
+ saveConvergedState( subRegion ); // necessary for a meaningful porosity update in sequential schemes
updatePorosityAndPermeability( subRegion );
// Now, we initialize and update each constitutive model one by one
@@ -402,9 +599,9 @@ void ImmiscibleMultiphaseFlow::initializeFluidState( MeshLevel & mesh,
string const & relpermName = subRegion.template getReference< string >( viewKeyStruct::relPermNamesString() );
RelativePermeabilityBase & relPermMaterial =
getConstitutiveModel< RelativePermeabilityBase >( subRegion, relpermName );
- relPermMaterial.saveConvergedPhaseVolFractionState( phaseVolFrac ); // this needs to happen before calling updateRelPermModel
+ relPermMaterial.saveConvergedPhaseVolFractionState( phaseVolFrac ); // this needs to happen before calling updateRelPermModel
updateRelPermModel( subRegion );
- relPermMaterial.saveConvergedState(); // this needs to happen after calling updateRelPermModel
+ relPermMaterial.saveConvergedState(); // this needs to happen after calling updateRelPermModel
// 4.4 Then, we initialize/update the capillary pressure model
//
@@ -425,6 +622,7 @@ void ImmiscibleMultiphaseFlow::initializeFluidState( MeshLevel & mesh,
CapillaryPressureBase const & capPressureMaterial =
getConstitutiveModel< CapillaryPressureBase >( subRegion, capPressureName );
capPressureMaterial.initializeRockState( porosity, permeability ); // this needs to happen before calling updateCapPressureModel
+ capPressureMaterial.saveConvergedPhaseVolFractionState( phaseVolFrac );
updateCapPressureModel( subRegion );
}
@@ -473,6 +671,53 @@ void ImmiscibleMultiphaseFlow::initializePostInitialConditionsPreSubGroups()
CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, mesh, domain.getNeighbors(), false );
} );
+ // Retrieve the numerical methods and finite volume manager
+ FiniteVolumeManager const & fvManager = domain.getNumericalMethodManager().getFiniteVolumeManager();
+ FluxApproximationBase const & fluxApprox = fvManager.getFluxApproximation( m_discretizationName );
+ const geos::string flux_approximation_name = fluxApprox.getName();
+
+ // Clear the existing mapping between connector indices and interface region indices
+ m_interfaceRegionByConnector.clear();
+ m_iconnToGlobalFace.clear();
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( std::string const &,
+ MeshLevel & meshLevel,
+ string_array const & GEOS_UNUSED_PARAM( regionNames ))
+ {
+ // Access the face manager and retrieve the face set group for the current mesh level
+ FaceManager const & faceManager = meshLevel.getFaceManager();
+ Group const & faceSetGroup = faceManager.sets();
+ arrayView1d< globalIndex const > const faceLocalToGlobal = faceManager.localToGlobalMap();
+
+ // Access the connector indices map (face index → connector index)
+ Group & stencilGroup =
+ meshLevel.getGroup( FluxApproximationBase::groupKeyStruct::stencilMeshGroupString())
+ .getGroup( flux_approximation_name );
+ CellElementStencilTPFA & stencil =
+ stencilGroup.getReference< CellElementStencilTPFA >(
+ FluxApproximationBase::viewKeyStruct::cellStencilString());
+ unordered_map< localIndex, localIndex > const & connectorIndices = stencil.getConnectorIndices();
+
+ // for all interface face sets to map connector indices to their corresponding interface region indices
+ for( size_t surfaceRegionIndex = 0; surfaceRegionIndex < m_interfaceFaceSetNames.size(); ++surfaceRegionIndex )
+ {
+ // Iterate over each face and associate its connector index
+ std::string const & faceSetName = m_interfaceFaceSetNames[surfaceRegionIndex];
+ for( localIndex kf : faceSetGroup.getReference< SortedArray< localIndex > >( faceSetName ))
+ {
+ auto it = connectorIndices.find( kf );
+ if( it != connectorIndices.end())
+ {
+ localIndex const iconn = it->second;
+ // Map the connector index to the corresponding surface region index
+ m_interfaceRegionByConnector[iconn] = surfaceRegionIndex;
+ // Map the connector index to the global face index for MPI-invariant warm-start
+ m_iconnToGlobalFace[iconn] = faceLocalToGlobal[kf];
+ }
+ }
+ }
+ } );
+
+
initializeState( domain );
}
@@ -582,7 +827,7 @@ void ImmiscibleMultiphaseFlow::assembleAccumulationTerm( DomainPartition & domai
}
void ImmiscibleMultiphaseFlow::assembleFluxTerms( real64 const dt,
- DomainPartition const & domain,
+ DomainPartition & domain,
DofManager const & dofManager,
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs ) const
@@ -595,30 +840,108 @@ void ImmiscibleMultiphaseFlow::assembleFluxTerms( real64 const dt,
string const & dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() );
+
forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel const & mesh,
- string_array const & )
+ MeshLevel & mesh,
+ string_array const & regionNames )
{
- fluxApprox.forAllStencils( mesh, [&]( auto & stencil )
+ if( m_hasCapPressure )
{
- typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper();
- immiscibleMultiphaseKernels::
- FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( m_numPhases,
- dofManager.rankOffset(),
- dofKey,
- m_hasCapPressure,
- m_useTotalMassEquation,
- m_gravityDensityScheme == GravityDensityScheme::PhasePresence,
- getName(),
- mesh.getElemManager(),
- stencilWrapper,
- dt,
- localMatrix.toViewConstSizes(),
- localRhs.toView() );
- } );
+ // Get the first subregion to pass to the kernel factory (only used for domainSize, not for filtering connections)
+ ElementSubRegionBase const * firstSubRegion = nullptr;
+ mesh.getElemManager().forElementSubRegions( regionNames,
+ [&]( localIndex const,
+ ElementSubRegionBase const & subRegion )
+ {
+ if( firstSubRegion == nullptr )
+ {
+ firstSubRegion = &subRegion;
+ }
+ } );
+
+ fluxApprox.forAllStencils( mesh, [&]( auto & stencil )
+ {
+ typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper();
+
+ // Build flat warm-start array from MPI-invariant global map.
+ // Each interface connection's warm-start Pc is keyed by global face index in
+ // m_convergedPcIntByGlobalFace, ensuring identical initial guesses regardless of
+ // MPI partitioning.
+ localIndex const numConn = stencilWrapper.size();
+ array1d< real64 > convergedPcInt( numConn );
+ convergedPcInt.setValues< serialPolicy >( -1.0 );
+ for( auto const & entry : m_iconnToGlobalFace )
+ {
+ localIndex const iconn = entry.first;
+ globalIndex const globalFace = entry.second;
+ if( iconn < numConn )
+ {
+ auto pcIt = m_convergedPcIntByGlobalFace.find( globalFace );
+ if( pcIt != m_convergedPcIntByGlobalFace.end() )
+ {
+ convergedPcInt[iconn] = pcIt->second;
+ }
+ }
+ }
+
+ immiscibleMultiphaseKernels::
+ FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( m_numPhases,
+ dofManager.rankOffset(),
+ dofKey,
+ m_hasCapPressure,
+ m_useTotalMassEquation,
+ m_gravityDensityScheme == GravityDensityScheme::PhasePresence,
+ getName(),
+ mesh.getElemManager(),
+ stencilWrapper,
+ m_interfaceFaceSetNames,
+ m_interfaceConstitutivePairs,
+ m_interfacePairRegionIndices,
+ m_interfaceRegionByConnector,
+ *firstSubRegion,
+ dt,
+ localMatrix.toViewConstSizes(),
+ localRhs.toView(),
+ convergedPcInt.toView() );
+
+ // Read back updated warm-start values into MPI-invariant global map
+ for( auto const & entry : m_iconnToGlobalFace )
+ {
+ localIndex const iconn = entry.first;
+ globalIndex const globalFace = entry.second;
+ if( iconn < numConn && convergedPcInt[iconn] > 0.0 )
+ {
+ m_convergedPcIntByGlobalFace[globalFace] = convergedPcInt[iconn];
+ }
+ }
+ } );
+ }
+ else
+ {
+ fluxApprox.forAllStencils( mesh, [&]( auto & stencil )
+ {
+ typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper();
+ immiscibleMultiphaseKernels::
+ FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( m_numPhases,
+ dofManager.rankOffset(),
+ dofKey,
+ m_hasCapPressure,
+ m_useTotalMassEquation,
+ m_gravityDensityScheme == GravityDensityScheme::PhasePresence,
+ getName(),
+ mesh.getElemManager(),
+ stencilWrapper,
+ dt,
+ localMatrix.toViewConstSizes(),
+ localRhs.toView() );
+ } );
+ }
+
} );
}
+// Ryan: Looks like this will need to be overwritten as well...
+// I have left the CompositionalMultiphaseFVM implementation for reference
void ImmiscibleMultiphaseFlow::setupDofs( DomainPartition const & domain,
DofManager & dofManager ) const
{
@@ -723,16 +1046,14 @@ bool ImmiscibleMultiphaseFlow::validateDirichletBC( DomainPartition & domain,
{
bcConsistent = false;
GEOS_WARNING( BCMessage::missingPressure( regionName, subRegionName, setName,
- fields::flow::pressure::key() ),
- getDataContext() );
+ fields::flow::pressure::key() ) );
}
if( comp < 0 || comp >= m_numPhases )
{
bcConsistent = false;
GEOS_WARNING( BCMessage::invalidComponentIndex( comp, fs.getName(),
- fields::immiscibleMultiphaseFlow::phaseVolumeFraction::key() ),
- getDataContext() );
- return; // can't check next part with invalid component id
+ fields::immiscibleMultiphaseFlow::phaseVolumeFraction::key() ) );
+ return; // can't check next part with invalid component id
}
ComponentMask< MAX_NP > & compMask = subRegionSetMap[setName];
@@ -742,11 +1063,9 @@ bool ImmiscibleMultiphaseFlow::validateDirichletBC( DomainPartition & domain,
fsManager.forSubGroups< EquilibriumInitialCondition >( [&] ( EquilibriumInitialCondition const & bc )
{
string_array const & componentNames = bc.getComponentNames();
- GEOS_UNUSED_VAR( componentNames );
GEOS_WARNING( BCMessage::conflictingComposition( comp, componentNames[comp],
regionName, subRegionName, setName,
- fields::immiscibleMultiphaseFlow::phaseVolumeFraction::key() )
- , getDataContext() );
+ fields::immiscibleMultiphaseFlow::phaseVolumeFraction::key() ) );
} );
}
compMask.set( comp );
@@ -797,7 +1116,7 @@ void ImmiscibleMultiphaseFlow::applyDirichletBC( real64 const time_n,
if( m_nonlinearSolverParameters.m_numNewtonIterations == 0 )
{
bool const bcConsistent = validateDirichletBC( domain, time_n + dt );
- GEOS_ERROR_IF( !bcConsistent, "ImmiscibleMultiphaseFlow : inconsistent boundary conditions", getDataContext() );
+ GEOS_ERROR_IF( !bcConsistent, GEOS_FMT( "ImmiscibleMultiphaseFlow {}: inconsistent boundary conditions", getDataContext() ) );
}
FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance();
@@ -1018,7 +1337,7 @@ void ImmiscibleMultiphaseFlow::applySourceFluxBC( real64 const time,
return;
}
- real64 const rhsValue = rhsContributionArrayView[a] / sizeScalingFactor; // scale the contribution by the sizeScalingFactor here!
+ real64 const rhsValue = rhsContributionArrayView[a] / sizeScalingFactor; // scale the contribution by the sizeScalingFactor here!
massProd += rhsValue;
if( useTotalMassEquation > 0 )
{
@@ -1027,7 +1346,7 @@ void ImmiscibleMultiphaseFlow::applySourceFluxBC( real64 const time,
localRhs[totalMassBalanceRow] += rhsValue;
if( fluidPhaseId < numFluidPhases - 1 )
{
- globalIndex const compMassBalanceRow = totalMassBalanceRow + fluidPhaseId + 1; // component mass bal equations are shifted
+ globalIndex const compMassBalanceRow = totalMassBalanceRow + fluidPhaseId + 1; // component mass bal equations are shifted
localRhs[compMassBalanceRow] += rhsValue;
}
}
@@ -1128,8 +1447,6 @@ real64 ImmiscibleMultiphaseFlow::calculateResidualNorm( real64 const & GEOS_UNUS
GEOS_LOG_LEVEL_RANK_0_NLR( logInfo::ResidualNorm, GEOS_FMT( " ( R{} ) = ( {:4.2e} )",
coupledSolverAttributePrefix(), residualNorm ))
- getConvergenceStats().setResidualValue( GEOS_FMT( "R{}", coupledSolverAttributePrefix()), residualNorm );
-
return residualNorm;
}
@@ -1162,7 +1479,7 @@ void ImmiscibleMultiphaseFlow::applySystemSolution( DofManager const & dofManage
MeshLevel & mesh,
string_array const & regionNames )
{
- stdVector< string > fields{ fields::flow::pressure::key(), fields::immiscibleMultiphaseFlow::phaseVolumeFraction::key() };
+ std::vector< string > fields{ fields::flow::pressure::key(), fields::immiscibleMultiphaseFlow::phaseVolumeFraction::key() };
FieldIdentifiers fieldsToBeSync;
fieldsToBeSync.addElementFields( fields, regionNames );
@@ -1180,6 +1497,7 @@ void ImmiscibleMultiphaseFlow::updateVolumeConstraint( ElementSubRegionBase & su
forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
{
+ phaseVolumeFraction[ei][0] = fmin( 1.0, fmax( phaseVolumeFraction[ei][0], 0.0 ));;
phaseVolumeFraction[ei][1] = 1.0 - phaseVolumeFraction[ei][0];
} );
}
@@ -1258,11 +1576,11 @@ void ImmiscibleMultiphaseFlow::implicitStepComplete( real64 const & time,
CoupledSolidBase const & porousMaterial = getConstitutiveModel< CoupledSolidBase >( subRegion, solidName );
if( m_keepVariablesConstantDuringInitStep )
{
- porousMaterial.ignoreConvergedState(); // newPorosity <- porosity_n
+ porousMaterial.ignoreConvergedState(); // newPorosity <- porosity_n
}
else
{
- porousMaterial.saveConvergedState(); // porosity_n <- porosity
+ porousMaterial.saveConvergedState(); // porosity_n <- porosity
}
// Step 4: save converged state for the relperm model to handle hysteresis
@@ -1288,10 +1606,10 @@ void ImmiscibleMultiphaseFlow::implicitStepComplete( real64 const & time,
CapillaryPressureBase const & capPressureMaterial =
getConstitutiveModel< CapillaryPressureBase >( subRegion, capPressName );
capPressureMaterial.saveConvergedRockState( porosity, permeability );
+ capPressureMaterial.saveConvergedPhaseVolFractionState( phaseVolFrac );
}
} );
} );
-
}
void ImmiscibleMultiphaseFlow::saveConvergedState( ElementSubRegionBase & subRegion ) const
@@ -1411,4 +1729,4 @@ real64 ImmiscibleMultiphaseFlow::setNextDtBasedOnStateChange( real64 const & cur
REGISTER_CATALOG_ENTRY( PhysicsSolverBase, ImmiscibleMultiphaseFlow, string const &, Group * const )
-} // namespace geos
+} // namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlow.hpp b/src/coreComponents/physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlow.hpp
index 7526130316c..87fc223f3ab 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlow.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlow.hpp
@@ -27,6 +27,12 @@
namespace geos
{
+
+namespace constitutive
+{
+class ConstitutiveBase;
+} // namespace constitutive
+
//START_SPHINX_INCLUDE_00
/**
* @class ImmiscibleMultiphaseFlow
@@ -160,12 +166,11 @@ class ImmiscibleMultiphaseFlow : public FlowSolverBase
* @param matrix the system matrix
* @param rhs the system right-hand side vector
*/
- virtual void
- assembleFluxTerms( real64 const dt,
- DomainPartition const & domain,
- DofManager const & dofManager,
- CRSMatrixView< real64, globalIndex const > const & localMatrix,
- arrayView1d< real64 > const & localRhs ) const;
+ void assembleFluxTerms( real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) const;
/**
* @brief Function to perform the Application of Dirichlet type BC's
@@ -215,6 +220,10 @@ class ImmiscibleMultiphaseFlow : public FlowSolverBase
struct viewKeyStruct : public FlowSolverBase::viewKeyStruct
{
// inputs
+ static constexpr char const * capPressureNamesString() { return "capPressureNames"; }
+ static constexpr char const * relPermNamesString() { return "relPermNames"; }
+ static constexpr char const * elemDofFieldString() { return "elemDofField"; }
+ static constexpr char const * interfaceFaceSetNamesString() { return "interfaceFaceSetNames"; }
// density averaging scheme
static constexpr char const * gravityDensitySchemeString() { return "gravityDensityScheme"; }
@@ -228,9 +237,9 @@ class ImmiscibleMultiphaseFlow : public FlowSolverBase
static constexpr char const * maxRelativePresChangeString() { return "maxRelativePressureChange"; }
static constexpr char const * useTotalMassEquationString() { return "useTotalMassEquation"; }
- static constexpr char const * capPressureNamesString() { return "capillary_pressure"; }
- static constexpr char const * relPermNamesString() { return "relative_permeability"; }
- static constexpr char const * elemDofFieldString() { return "elemDofField"; }
+// static constexpr char const * capPressureNamesString() { return "capillary_pressure"; }
+// static constexpr char const * relPermNamesString() { return "relative_permeability"; }
+// static constexpr char const * elemDofFieldString() { return "elemDofField"; }
};
@@ -300,6 +309,29 @@ class ImmiscibleMultiphaseFlow : public FlowSolverBase
/// damping factor for solution change targets
real64 m_solutionChangeScalingFactor;
+ string_array m_interfaceFaceSetNames;
+
+ stdVector< std::array< std::tuple< constitutive::RelativePermeabilityBase *,
+ constitutive::CapillaryPressureBase *,
+ constitutive::TwoPhaseImmiscibleFluid * >, 2 > > m_interfaceConstitutivePairs;
+
+ /// For each surface region, the element region index for side 0 and side 1 of the interface pair.
+ /// Used to match stencil cell ordering to the constitutive pair ordering.
+ stdVector< std::array< localIndex, 2 > > m_interfacePairRegionIndices;
+
+ unordered_map< localIndex, localIndex > m_interfaceRegionByConnector;
+ unordered_map< localIndex, localIndex > m_connectorIndicesByInterfaceRegion;
+
+ /// Warm-start capillary pressure at interface connections, keyed by global face index.
+ /// This ensures MPI-invariant warm-start across different partitioning configurations.
+ /// Marked mutable because it is a convergence cache updated during const assembleSystem().
+ mutable std::unordered_map< globalIndex, real64 > m_convergedPcIntByGlobalFace;
+
+ /// Mapping from local connection index (iconn) to global face index for interface connections.
+ /// Built once in initializePostInitialConditionsPreSubGroups and used to populate/read-back
+ /// the warm-start array for the flux kernel.
+ std::unordered_map< localIndex, globalIndex > m_iconnToGlobalFace;
+
private:
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/CapillaryPressureUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/CapillaryPressureUpdateKernel.hpp
new file mode 100644
index 00000000000..2a02f536ea9
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/CapillaryPressureUpdateKernel.hpp
@@ -0,0 +1,73 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 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 CapillaryPressureUpdateKernel.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_IMMISCIBLEMULTIPHASE_CAPILLARYPRESSUREUPDATEKERNEL_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_IMMISCIBLEMULTIPHASE_CAPILLARYPRESSUREUPDATEKERNEL_HPP
+
+#include "common/DataTypes.hpp"
+#include "common/GEOS_RAJA_Interface.hpp"
+
+namespace geos
+{
+
+namespace immiscibleMultiphaseKernels
+{
+
+/******************************** CapillaryPressureUpdateKernel ********************************/
+
+struct CapillaryPressureUpdateKernel
+{
+ template< typename POLICY, typename CAPPRES_WRAPPER >
+ static void
+ launch( localIndex const size,
+ CAPPRES_WRAPPER const & capPresWrapper,
+ arrayView2d< real64 const, immiscibleFlow::USD_PHASE > const & phaseVolFrac )
+ {
+ forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k )
+ {
+ for( localIndex q = 0; q < capPresWrapper.numGauss(); ++q )
+ {
+ capPresWrapper.update( k, q, phaseVolFrac[k] );
+ }
+ } );
+ }
+
+ template< typename POLICY, typename CAPPRES_WRAPPER >
+ static void
+ launch( SortedArrayView< localIndex const > const & targetSet,
+ CAPPRES_WRAPPER const & capPresWrapper,
+ arrayView2d< real64 const, immiscibleFlow::USD_PHASE > const & phaseVolFrac )
+ {
+ forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a )
+ {
+ localIndex const k = targetSet[a];
+ for( localIndex q = 0; q < capPresWrapper.numGauss(); ++q )
+ {
+ capPresWrapper.update( k, q, phaseVolFrac[k] );
+ }
+ } );
+ }
+};
+
+} // namespace immiscibleMultiphaseKernels
+
+} // namespace geos
+
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_IMMISCIBLEMULTIPHASE_CAPILLARYPRESSUREUPDATEKERNEL_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/ImmiscibleMultiphaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/ImmiscibleMultiphaseKernels.hpp
index ebb78332b43..ee910298dfc 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/ImmiscibleMultiphaseKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/ImmiscibleMultiphaseKernels.hpp
@@ -17,39 +17,2254 @@
* @file ImmiscibleMultiphaseKernels.hpp
*/
+
#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_MULTIPHASEKERNELS_HPP
#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_MULTIPHASEKERNELS_HPP
-#include "codingUtilities/Utilities.hpp"
-#include "common/DataLayouts.hpp"
-#include "common/DataTypes.hpp"
-#include "common/GEOS_RAJA_Interface.hpp"
+
+ #include "codingUtilities/Utilities.hpp"
+ #include "common/DataLayouts.hpp"
+ #include "common/DataTypes.hpp"
+ #include "common/GEOS_RAJA_Interface.hpp"
+ #include "constitutive/fluid/twophaseimmisciblefluid/TwoPhaseImmiscibleFluid.hpp"
+ #include "constitutive/solid/CoupledSolidBase.hpp"
+ #include "constitutive/fluid/twophaseimmisciblefluid/TwoPhaseImmiscibleFluidFields.hpp"
+ #include "constitutive/capillaryPressure/CapillaryPressureFields.hpp"
+ #include "constitutive/capillaryPressure/CapillaryPressureBase.hpp"
+ #include "constitutive/capillaryPressure/JFunctionCapillaryPressure.hpp"
+ #include "constitutive/capillaryPressure/TableCapillaryPressure.hpp"
+ #include "constitutive/capillaryPressure/TableCapillaryPressureHysteresis.hpp"
+ #include "constitutive/permeability/PermeabilityBase.hpp"
+ #include "constitutive/permeability/PermeabilityFields.hpp"
+ #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp"
+ #include "constitutive/relativePermeability/RelativePermeabilityFields.hpp"
+ #include "constitutive/ConstitutiveManager.hpp"
+#include "constitutive/capillaryPressure/CapillaryPressureSelector.hpp"
+#include "constitutive/relativePermeability/RelativePermeabilitySelector.hpp"
+
+#include "constitutive/ConstitutivePassThru.hpp"
#include "constitutive/fluid/twophaseimmisciblefluid/TwoPhaseImmiscibleFluid.hpp"
-#include "constitutive/solid/CoupledSolidBase.hpp"
-#include "constitutive/fluid/twophaseimmisciblefluid/TwoPhaseImmiscibleFluidFields.hpp"
-#include "constitutive/capillaryPressure/CapillaryPressureFields.hpp"
-#include "constitutive/capillaryPressure/CapillaryPressureBase.hpp"
-#include "constitutive/permeability/PermeabilityBase.hpp"
-#include "constitutive/permeability/PermeabilityFields.hpp"
-#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp"
-#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp"
-#include "fieldSpecification/AquiferBoundaryCondition.hpp"
-#include "finiteVolume/BoundaryStencil.hpp"
-#include "finiteVolume/FluxApproximationBase.hpp"
-#include "linearAlgebra/interfaces/InterfaceTypes.hpp"
-#include "physicsSolvers/PhysicsSolverBaseKernels.hpp"
-#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp"
-#include "physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlowFields.hpp"
-#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp"
-#include "physicsSolvers/fluidFlow/StencilAccessors.hpp"
-#include "physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/KernelLaunchSelectors.hpp"
+
+
+ #include "fieldSpecification/AquiferBoundaryCondition.hpp"
+ #include "finiteVolume/BoundaryStencil.hpp"
+ #include "finiteVolume/CellElementStencilTPFA.hpp"
+ #include "finiteVolume/FluxApproximationBase.hpp"
+ #include "linearAlgebra/interfaces/InterfaceTypes.hpp"
+ #include "physicsSolvers/PhysicsSolverBaseKernels.hpp"
+ #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp"
+ #include "physicsSolvers/fluidFlow/ImmiscibleMultiphaseFlowFields.hpp"
+ #include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp"
+ #include "physicsSolvers/fluidFlow/StencilAccessors.hpp"
+ #include "physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp"
+ #include "physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp"
+ #include "physicsSolvers/PhysicsSolverBaseKernels.hpp"
+ #include "physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/KernelLaunchSelectors.hpp"
+ #include "physicsSolvers/fluidFlow/kernels/immiscibleMultiphase/KernelLaunchSelectors.hpp"
+
namespace geos
{
namespace immiscibleMultiphaseKernels
{
+
using namespace constitutive;
+GEOS_HOST_DEVICE
+inline
+constexpr bool ENABLE_LOCAL_SOLVER_DEBUG = false;
+
+static void local_solver( real64 uT, stdVector< real64 > const & saturations, stdVector< real64 > const & pressures, stdVector< real64 > const & JFMultipliers,
+ stdVector< real64 > const & trappedSats1,
+ stdVector< real64 > const & trappedSats2, stdVector< fields::cappres::ModeIndexType > const & modes, stdVector< real64 > const & transHat,
+ stdVector< real64 > const & dTransHat_dP, stdVector< real64 > const & gravCoefHat, stdVector< real64 > const & gravCoef,
+ stdVector< real64 > const & cellCenterDuT, stdVector< real64 > const & cellCenterDens, stdVector< real64 > const & cellCenterDens_dP,
+ std::vector< RelativePermeabilityBase * > const & relPerms, std::vector< CapillaryPressureBase * > const & capPressures,
+ std::vector< TwoPhaseImmiscibleFluid * > const & fluids, stdVector< real64 > & phi, stdVector< real64 > & grad_phi_P, stdVector< real64 > & grad_phi_S, bool & converged,
+ stdVector< real64 > const & phaseMaxHistVolFrac1, stdVector< real64 > const & phaseMinHistVolFrac1,
+ stdVector< real64 > const & phaseMaxHistVolFrac2, stdVector< real64 > const & phaseMinHistVolFrac2,
+ real64 & warmStartPc )
+{
+
+ // getting wrappers:
+
+ constitutive::constitutiveUpdatePassThru( *capPressures[0], [&] ( auto & castedCapPres1 )
+ {
+ auto capPresWrapper1 = castedCapPres1.createKernelWrapper();
+
+
+ constitutive::constitutiveUpdatePassThru( *capPressures[1], [&] ( auto & castedCapPres2 )
+ {
+ auto capPresWrapper2 = castedCapPres2.createKernelWrapper();
+
+
+ constitutive::constitutiveUpdatePassThru( *relPerms[0], [&] ( auto & castedRelPerm1 )
+ {
+ auto relPermWrapper1 = castedRelPerm1.createKernelWrapper();
+
+
+ constitutive::constitutiveUpdatePassThru( *relPerms[1], [&] ( auto & castedRelPerm2 )
+ {
+ auto relPermWrapper2 = castedRelPerm2.createKernelWrapper();
+
+ auto fluidWrapper1 = fluids[0]->createKernelWrapper();
+ auto fluidWrapper2 = fluids[1]->createKernelWrapper();
+
+
+ // std::ofstream outFile( "iterations2.csv" );
+
+
+ // // Write data to the file
+ // outFile << "Jacobian";
+ // outFile << ",";
+ // outFile << "residual";
+ // outFile << ",";
+ // outFile << "Fw_alpha";
+ // outFile << ",";
+ // outFile << "Fw_beta";
+ // outFile << ",";
+ // outFile << "Pc_int";
+ // outFile << ",";
+ // outFile << "Pc_int1";
+ // outFile << ",";
+ // outFile << "Pc_int2";
+ // outFile << ",";
+ // outFile << "Fn_alpha";
+ // outFile << ",";
+ // outFile << "Fn_beta";
+ // outFile << ",";
+ // outFile << "Vw_alpha";
+ // outFile << ",";
+ // outFile << "Vn_alpha";
+ // outFile << ",";
+ // outFile << "Vw_beta";
+ // outFile << ",";
+ // outFile << "Vn_beta";
+ // outFile << ",";
+ // outFile << "Gw_alpha";
+ // outFile << ",";
+ // outFile << "Gn_alpha";
+ // outFile << ",";
+ // outFile << "Gw_beta";
+ // outFile << ",";
+ // outFile << "Gn_beta";
+ // outFile << ",";
+ // outFile << "Cw_alpha";
+ // outFile << ",";
+ // outFile << "Cn_alpha";
+ // outFile << ",";
+ // outFile << "Cw_beta";
+ // outFile << ",";
+ // outFile << "Cn_beta";
+ // outFile << ",";
+ // outFile << "transHats0";
+ // outFile << ",";
+ // outFile << "transHats1";
+ // outFile << ",";
+ // outFile << "gravCoefHats";
+ // outFile << ",";
+ // outFile << "gravCoef0";
+ // outFile << ",";
+ // outFile << "gravCoef1";
+ // outFile << ",";
+ // outFile << "uT";
+ // outFile << ",";
+ // outFile << "duT_dP0";
+ // outFile << ",";
+ // outFile << "duT_dS0";
+ // outFile << ",";
+ // outFile << "duT_dP1";
+ // outFile << ",";
+ // outFile << "duT_dS1";
+ // outFile << std::endl;
+
+
+
+ // nonlinear solver's parameters
+ real64 tol = 1.0e-10;
+ int max_iter = 100;
+ converged = 0;
+ bool damping = true;
+
+ // Local newton loop:
+
+ // Use of the capillary pressure kernel wrapper
+
+ StackArray< real64, 2, 2, immiscibleFlow::LAYOUT_PHASE > phaseVolFrac1( 1, 2 );
+ StackArray< real64, 3, 2, constitutive::cappres::LAYOUT_CAPPRES > capPres1( 1, 1, 2 );
+ StackArray< real64, 4, 4, constitutive::cappres::LAYOUT_CAPPRES_DS > dPhaseVolFrac_dCapPres1( 1, 1, 2, 2 );
+ StackArray< real64, 4, 4, constitutive::cappres::LAYOUT_CAPPRES_DS > dCapPres1_dPhaseVolFrac( 1, 1, 2, 2 );
+ StackArray< real64, 3, 2, constitutive::relperm::LAYOUT_RELPERM > trappedVolFrac1( 1, 1, 2 );
+ StackArray< real64, 2, 2, immiscibleFlow::LAYOUT_PHASE > facePhaseVolFrac1( 1, 2 );
+ StackArray< real64, 3, 2, constitutive::relperm::LAYOUT_RELPERM > faceTrappedVolFrac1( 1, 1, 2 );
+ StackArray< real64, 3, 2, constitutive::cappres::LAYOUT_CAPPRES > faceCapPres1( 1, 1, 2 );
+ StackArray< real64, 4, 4, constitutive::cappres::LAYOUT_CAPPRES_DS > dfacePhaseVolFrac_dCapPres1( 1, 1, 2, 2 );
+ StackArray< real64, 4, 4, constitutive::cappres::LAYOUT_CAPPRES_DS > dCapPres1_dfacePhaseVolFrac( 1, 1, 2, 2 );
+ StackArray< real64, 2, 2, immiscibleFlow::LAYOUT_PHASE > phaseVolFrac2( 1, 2 );
+ StackArray< real64, 3, 2, constitutive::cappres::LAYOUT_CAPPRES > capPres2( 1, 1, 2 );
+ StackArray< real64, 4, 4, constitutive::cappres::LAYOUT_CAPPRES_DS > dPhaseVolFrac_dCapPres2( 1, 1, 2, 2 );
+ StackArray< real64, 4, 4, constitutive::cappres::LAYOUT_CAPPRES_DS > dCapPres2_dPhaseVolFrac( 1, 1, 2, 2 );
+ StackArray< real64, 3, 2, constitutive::relperm::LAYOUT_RELPERM > trappedVolFrac2( 1, 1, 2 );
+ StackArray< real64, 2, 2, immiscibleFlow::LAYOUT_PHASE > facePhaseVolFrac2( 1, 2 );
+ StackArray< real64, 3, 2, constitutive::relperm::LAYOUT_RELPERM > faceTrappedVolFrac2( 1, 1, 2 );
+ StackArray< real64, 3, 2, constitutive::cappres::LAYOUT_CAPPRES > faceCapPres2( 1, 1, 2 );
+ StackArray< real64, 4, 4, constitutive::cappres::LAYOUT_CAPPRES_DS > dfacePhaseVolFrac_dCapPres2( 1, 1, 2, 2 );
+ StackArray< real64, 4, 4, constitutive::cappres::LAYOUT_CAPPRES_DS > dCapPres2_dfacePhaseVolFrac( 1, 1, 2, 2 );
+ StackArray< real64, 1, 2 > JFunc1( 2 );
+ StackArray< real64, 1, 2 > JFunc2( 2 );
+
+
+ StackArray< real64, 2, 2, immiscibleFlow::LAYOUT_PHASE > phaseMaxHistoricalVolFraction1( 1, 2 );
+ StackArray< real64, 2, 2, immiscibleFlow::LAYOUT_PHASE > phaseMinHistoricalVolFraction1( 1, 2 );
+ StackArray< real64, 2, 2, immiscibleFlow::LAYOUT_PHASE > phaseMaxHistoricalVolFraction2( 1, 2 );
+ StackArray< real64, 2, 2, immiscibleFlow::LAYOUT_PHASE > phaseMinHistoricalVolFraction2( 1, 2 );
+ StackArray< real64, 2, 2, compflow::LAYOUT_PHASE > phaseMode2PeakVolFraction1( 1, 2 );
+ StackArray< real64, 2, 2, compflow::LAYOUT_PHASE > phaseMode2PeakVolFraction2( 1, 2 );
+ phaseMode2PeakVolFraction1[0][0] = 0.0;
+ phaseMode2PeakVolFraction1[0][1] = 0.0;
+ phaseMode2PeakVolFraction2[0][0] = 0.0;
+ phaseMode2PeakVolFraction2[0][1] = 0.0;
+ arraySlice1d< real64, compflow::USD_PHASE - 1 > phaseMode2PeakSlice1 = phaseMode2PeakVolFraction1[0];
+ arraySlice1d< real64, compflow::USD_PHASE - 1 > phaseMode2PeakSlice2 = phaseMode2PeakVolFraction2[0];
+
+ if( phaseMaxHistVolFrac1.size() >= 2 && phaseMaxHistVolFrac1[0] >= 0.0 )
+ {
+
+ phaseMaxHistoricalVolFraction1[0][0] = phaseMaxHistVolFrac1[0];
+ phaseMaxHistoricalVolFraction1[0][1] = phaseMaxHistVolFrac1[1];
+ phaseMinHistoricalVolFraction1[0][0] = phaseMinHistVolFrac1[0];
+ phaseMinHistoricalVolFraction1[0][1] = phaseMinHistVolFrac1[1];
+ }
+ else
+ {
+
+ phaseMaxHistoricalVolFraction1[0][0] = saturations[0];
+ phaseMaxHistoricalVolFraction1[0][1] = 1.0 - saturations[0];
+ phaseMinHistoricalVolFraction1[0][0] = saturations[0];
+ phaseMinHistoricalVolFraction1[0][1] = 1.0 - saturations[0];
+ }
+
+ if( phaseMaxHistVolFrac2.size() >= 2 && phaseMaxHistVolFrac2[0] >= 0.0 )
+ {
+
+ phaseMaxHistoricalVolFraction2[0][0] = phaseMaxHistVolFrac2[0];
+ phaseMaxHistoricalVolFraction2[0][1] = phaseMaxHistVolFrac2[1];
+ phaseMinHistoricalVolFraction2[0][0] = phaseMinHistVolFrac2[0];
+ phaseMinHistoricalVolFraction2[0][1] = phaseMinHistVolFrac2[1];
+ }
+ else
+ {
+ phaseMaxHistoricalVolFraction2[0][0] = saturations[1];
+ phaseMaxHistoricalVolFraction2[0][1] = 1.0 - saturations[1];
+ phaseMinHistoricalVolFraction2[0][0] = saturations[1];
+ phaseMinHistoricalVolFraction2[0][1] = 1.0 - saturations[1];
+ }
+
+ // compute relative permeability for both cell centers:
+
+ trappedVolFrac1[0][0][0] = trappedSats1[0];
+ trappedVolFrac1[0][0][1] = trappedSats1[1];
+
+ trappedVolFrac2[0][0][0] = trappedSats2[0];
+ trappedVolFrac2[0][0][1] = trappedSats2[1];
+
+ faceTrappedVolFrac1[0][0][0] = trappedSats1[0];
+ faceTrappedVolFrac1[0][0][1] = trappedSats1[1];
+
+ faceTrappedVolFrac2[0][0][0] = trappedSats2[0];
+ faceTrappedVolFrac2[0][0][1] = trappedSats2[1];
+
+ phaseVolFrac1[0][0] = saturations[0];
+ phaseVolFrac1[0][1] = 1.0 - saturations[0];
+
+ phaseVolFrac2[0][0] = saturations[1];
+ phaseVolFrac2[0][1] = 1.0 - saturations[1];
+
+ real64 Pc1_min = 0.0;
+ real64 Pc2_min = 0.0;
+ real64 Pc1_max = 0.0;
+ real64 Pc2_max = 0.0;
+
+ real64 density2[2]{};
+ real64 dDens_dP2[2][2]{};
+
+ density2[0] = cellCenterDens[0];
+ density2[1] = cellCenterDens[1];
+
+ dDens_dP2[0][0] = cellCenterDens_dP[0];
+ dDens_dP2[0][1] = cellCenterDens_dP[1];
+ dDens_dP2[1][0] = cellCenterDens_dP[2];
+ dDens_dP2[1][1] = cellCenterDens_dP[3];
+
+ JFunc1[0] = JFMultipliers[0];
+ JFunc2[0] = JFMultipliers[1];
+
+ using T1 = std::decay_t< decltype(castedCapPres1) >;
+ if constexpr (std::is_same_v< T1, JFunctionCapillaryPressure >) {
+ capPresWrapper1.compute( phaseVolFrac1[0],
+ JFunc1.toSliceConst(),
+ capPres1[0][0],
+ dCapPres1_dPhaseVolFrac[0][0] );
+
+ facePhaseVolFrac1[0][1] = 0.0;
+ facePhaseVolFrac1[0][0] = 1.0;
+ capPresWrapper1.compute( facePhaseVolFrac1[0],
+ JFunc1.toSliceConst(),
+ faceCapPres1[0][0],
+ dCapPres1_dfacePhaseVolFrac[0][0] );
+ Pc1_min = faceCapPres1[0][0][0];
+ facePhaseVolFrac1[0][1] = 1.0;
+ facePhaseVolFrac1[0][0] = 0.0;
+ capPresWrapper1.compute( facePhaseVolFrac1[0],
+ JFunc1.toSliceConst(),
+ faceCapPres1[0][0],
+ dCapPres1_dfacePhaseVolFrac[0][0] );
+ Pc1_max = faceCapPres1[0][0][0];
+
+ }
+ else if constexpr (std::is_same_v< T1, TableCapillaryPressureHysteresis >) {
+ auto preComputeMode0 = modes[0];
+ capPresWrapper1.compute( phaseVolFrac1[0],
+ phaseMaxHistoricalVolFraction1[0],
+ phaseMinHistoricalVolFraction1[0],
+ trappedVolFrac1[0][0],
+ capPres1[0][0],
+ dCapPres1_dPhaseVolFrac[0][0],
+ preComputeMode0,
+ phaseMode2PeakSlice1 );
+
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ std::cout << " [BOUNDS_DEBUG] Cell0: T1=TableCapillaryPressureHysteresis"
+ << ", preComputeMode=" << static_cast< int >(preComputeMode0)
+ << ", postComputeMode=" << static_cast< int >(modes[0])
+ << ", S=" << phaseVolFrac1[0][0]
+ << ", Pc=" << capPres1[0][0][0] << std::endl;
+ }
+
+ if( modes[0] == fields::cappres::ModeIndexType::DRAINAGE ||
+ modes[0] == fields::cappres::ModeIndexType::IMBIBITION )
+ {
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) { std::cout << " [BOUNDS_DEBUG] Cell0: DRAINAGE/IMBIBITION path" << std::endl; }
+ integer const tableIdx1 = static_cast< integer >(modes[0]);
+ real64 Pc1_at_S1, dPc1_at_S1;
+ real64 Pc1_at_S0, dPc1_at_S0;
+ real64 const S_one = 1.0;
+ real64 const S_zero = 0.0;
+ capPresWrapper1.computeRawTablePc( tableIdx1, S_one, Pc1_at_S1, dPc1_at_S1 );
+ capPresWrapper1.computeRawTablePc( tableIdx1, S_zero, Pc1_at_S0, dPc1_at_S0 );
+ Pc1_min = LvArray::math::min( Pc1_at_S1, Pc1_at_S0 );
+ Pc1_max = LvArray::math::max( Pc1_at_S1, Pc1_at_S0 );
+
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) { std::cout << " [BOUNDS_DEBUG] Cell0: Pc1_min=" << Pc1_min
+ << " (table@S=1:" << Pc1_at_S1 << ", table@S=0:" << Pc1_at_S0 << ")" << std::endl; }
+ }
+ else
+ {
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) { std::cout << " [BOUNDS_DEBUG] Cell0: SCANNING path, modes[0]=" << static_cast< int >(modes[0]) << std::endl; }
+ real64 const S_min_hist1 = phaseMinHistoricalVolFraction1[0][0];
+ real64 const S_max_hist1 = phaseMaxHistoricalVolFraction1[0][0];
+
+ auto scanBoundsMode1 = modes[0];
+
+ if( modes[0] == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ modes[0] == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE ||
+ modes[0] == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ capPresWrapper1.computeScanningCurvePcRange(
+ S_min_hist1, S_max_hist1, modes[0], Pc1_min, Pc1_max );
+ }
+ else
+ {
+ facePhaseVolFrac1[0][1] = 0.0;
+ facePhaseVolFrac1[0][0] = 1.0;
+ scanBoundsMode1 = modes[0];
+ capPresWrapper1.compute( facePhaseVolFrac1[0],
+ phaseMaxHistoricalVolFraction1[0],
+ phaseMinHistoricalVolFraction1[0],
+ faceTrappedVolFrac1[0][0],
+ faceCapPres1[0][0],
+ dCapPres1_dfacePhaseVolFrac[0][0],
+ scanBoundsMode1,
+ phaseMode2PeakSlice1 );
+ Pc1_min = faceCapPres1[0][0][0];
+
+ facePhaseVolFrac1[0][1] = 1.0;
+ facePhaseVolFrac1[0][0] = 0.0;
+ scanBoundsMode1 = modes[0];
+ capPresWrapper1.compute( facePhaseVolFrac1[0],
+ phaseMaxHistoricalVolFraction1[0],
+ phaseMinHistoricalVolFraction1[0],
+ faceTrappedVolFrac1[0][0],
+ faceCapPres1[0][0],
+ dCapPres1_dfacePhaseVolFrac[0][0],
+ scanBoundsMode1,
+ phaseMode2PeakSlice1 );
+ Pc1_max = faceCapPres1[0][0][0];
+ }
+ }
+ }
+ else
+ {
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) { std::cout << " [BOUNDS_DEBUG] Cell0: GENERIC (non-hysteresis) path" << std::endl; }
+ capPresWrapper1.compute( phaseVolFrac1[0],
+ capPres1[0][0],
+ dCapPres1_dPhaseVolFrac[0][0] );
+
+ facePhaseVolFrac1[0][1] = 0.0;
+ facePhaseVolFrac1[0][0] = 1.0;
+ capPresWrapper1.compute( facePhaseVolFrac1[0],
+ faceCapPres1[0][0],
+ dCapPres1_dfacePhaseVolFrac[0][0] );
+ Pc1_min = faceCapPres1[0][0][0];
+ facePhaseVolFrac1[0][1] = 1.0;
+ facePhaseVolFrac1[0][0] = 0.0;
+ capPresWrapper1.compute( facePhaseVolFrac1[0],
+ faceCapPres1[0][0],
+ dCapPres1_dfacePhaseVolFrac[0][0] );
+ Pc1_max = faceCapPres1[0][0][0];
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) { std::cout << " [BOUNDS_DEBUG] Cell0 GENERIC: Pc1_min=" << Pc1_min << ", Pc1_max=" << Pc1_max << std::endl; }
+ }
+
+ using T2 = std::decay_t< decltype(castedCapPres2) >;
+ if constexpr (std::is_same_v< T2, JFunctionCapillaryPressure >) {
+ // evaluating cell-center Pc:
+
+ capPresWrapper2.compute( phaseVolFrac2[0],
+ JFunc2.toSliceConst(),
+ capPres2[0][0],
+ dCapPres2_dPhaseVolFrac[0][0] );
+
+// finding endpoints:
+
+ facePhaseVolFrac2[0][1] = 0.0;
+ facePhaseVolFrac2[0][0] = 1.0;
+ capPresWrapper2.compute( facePhaseVolFrac2[0],
+ JFunc2.toSliceConst(),
+ faceCapPres2[0][0],
+ dCapPres2_dfacePhaseVolFrac[0][0] );
+ Pc2_min = faceCapPres2[0][0][0];
+ facePhaseVolFrac2[0][1] = 1.0;
+ facePhaseVolFrac2[0][0] = 0.0;
+ capPresWrapper2.compute( facePhaseVolFrac2[0],
+ JFunc2.toSliceConst(),
+ faceCapPres2[0][0],
+ dCapPres2_dfacePhaseVolFrac[0][0] );
+ Pc2_max = faceCapPres2[0][0][0];
+
+ }
+ else if constexpr (std::is_same_v< T2, TableCapillaryPressureHysteresis >) {
+ auto preComputeMode1 = modes[1];
+ capPresWrapper2.compute( phaseVolFrac2[0],
+ phaseMaxHistoricalVolFraction2[0],
+ phaseMinHistoricalVolFraction2[0],
+ trappedVolFrac2[0][0],
+ capPres2[0][0],
+ dCapPres2_dPhaseVolFrac[0][0],
+ preComputeMode1,
+ phaseMode2PeakSlice2 );
+
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ std::cout << " [BOUNDS_DEBUG] Cell1: T2=TableCapillaryPressureHysteresis"
+ << ", preComputeMode=" << static_cast< int >(preComputeMode1)
+ << ", postComputeMode=" << static_cast< int >(modes[1])
+ << ", S=" << phaseVolFrac2[0][0]
+ << ", Pc=" << capPres2[0][0][0] << std::endl;
+ }
+
+ if( modes[1] == fields::cappres::ModeIndexType::DRAINAGE ||
+ modes[1] == fields::cappres::ModeIndexType::IMBIBITION )
+ {
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) { std::cout << " [BOUNDS_DEBUG] Cell1: DRAINAGE/IMBIBITION path" << std::endl; }
+ integer const tableIdx2 = static_cast< integer >(modes[1]);
+ real64 Pc2_at_S1, dPc2_at_S1;
+ real64 Pc2_at_S0, dPc2_at_S0;
+ real64 const S_one_2 = 1.0;
+ real64 const S_zero_2 = 0.0;
+ capPresWrapper2.computeRawTablePc( tableIdx2, S_one_2, Pc2_at_S1, dPc2_at_S1 );
+ capPresWrapper2.computeRawTablePc( tableIdx2, S_zero_2, Pc2_at_S0, dPc2_at_S0 );
+ Pc2_min = LvArray::math::min( Pc2_at_S1, Pc2_at_S0 );
+ Pc2_max = LvArray::math::max( Pc2_at_S1, Pc2_at_S0 );
+
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) { std::cout << " [BOUNDS_DEBUG] Cell1: Pc2_min=" << Pc2_min
+ << " (table@S=1:" << Pc2_at_S1 << ", table@S=0:" << Pc2_at_S0 << ")" << std::endl; }
+ }
+ else
+ {
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) { std::cout << " [BOUNDS_DEBUG] Cell1: SCANNING path, modes[1]=" << static_cast< int >(modes[1]) << std::endl; }
+ real64 const S_min_hist2 = phaseMinHistoricalVolFraction2[0][0];
+ real64 const S_max_hist2 = phaseMaxHistoricalVolFraction2[0][0];
+ auto scanBoundsMode2 = modes[1];
+
+ if( modes[1] == fields::cappres::ModeIndexType::DRAINAGE_TO_IMBIBITION ||
+ modes[1] == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE ||
+ modes[1] == fields::cappres::ModeIndexType::IMBIBITION_TO_DRAINAGE_FROM_SCANNING )
+ {
+ capPresWrapper2.computeScanningCurvePcRange(
+ S_min_hist2, S_max_hist2, modes[1], Pc2_min, Pc2_max );
+ }
+ else
+ {
+ facePhaseVolFrac2[0][1] = 0.0;
+ facePhaseVolFrac2[0][0] = 1.0;
+ scanBoundsMode2 = modes[1];
+ capPresWrapper2.compute( facePhaseVolFrac2[0],
+ phaseMaxHistoricalVolFraction2[0],
+ phaseMinHistoricalVolFraction2[0],
+ faceTrappedVolFrac2[0][0],
+ faceCapPres2[0][0],
+ dCapPres2_dfacePhaseVolFrac[0][0],
+ scanBoundsMode2,
+ phaseMode2PeakSlice2 );
+ Pc2_min = faceCapPres2[0][0][0];
+
+ facePhaseVolFrac2[0][1] = 1.0;
+ facePhaseVolFrac2[0][0] = 0.0;
+ scanBoundsMode2 = modes[1];
+ capPresWrapper2.compute( facePhaseVolFrac2[0],
+ phaseMaxHistoricalVolFraction2[0],
+ phaseMinHistoricalVolFraction2[0],
+ faceTrappedVolFrac2[0][0],
+ faceCapPres2[0][0],
+ dCapPres2_dfacePhaseVolFrac[0][0],
+ scanBoundsMode2,
+ phaseMode2PeakSlice2 );
+ Pc2_max = faceCapPres2[0][0][0];
+ }
+ }
+ }
+ else
+ {
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) { std::cout << " [BOUNDS_DEBUG] Cell1: GENERIC (non-hysteresis) path" << std::endl; }
+ // evaluating cell-center Pc:
+
+ capPresWrapper2.compute( phaseVolFrac2[0],
+ capPres2[0][0],
+ dCapPres2_dPhaseVolFrac[0][0] );
+
+// finding endpoints:
+
+ facePhaseVolFrac2[0][1] = 0.0;
+ facePhaseVolFrac2[0][0] = 1.0;
+ capPresWrapper2.compute( facePhaseVolFrac2[0],
+ faceCapPres2[0][0],
+ dCapPres2_dfacePhaseVolFrac[0][0] );
+ Pc2_min = faceCapPres2[0][0][0];
+ facePhaseVolFrac2[0][1] = 1.0;
+ facePhaseVolFrac2[0][0] = 0.0;
+ capPresWrapper2.compute( facePhaseVolFrac2[0],
+ faceCapPres2[0][0],
+ dCapPres2_dfacePhaseVolFrac[0][0] );
+ Pc2_max = faceCapPres2[0][0][0];
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) { std::cout << " [BOUNDS_DEBUG] Cell1 GENERIC: Pc2_min=" << Pc2_min << ", Pc2_max=" << Pc2_max << std::endl; }
+ }
+
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ std::cout << " [BOUNDS_DEBUG] FINAL: modes[0]=" << static_cast< int >(modes[0])
+ << ", modes[1]=" << static_cast< int >(modes[1])
+ << ", Pc1_min=" << Pc1_min << ", Pc1_max=" << Pc1_max
+ << ", Pc2_min=" << Pc2_min << ", Pc2_max=" << Pc2_max << std::endl;
+ }
+
+ // Use of the relative permeability kernel wrapper
+
+
+ StackArray< real64, 3, 2, constitutive::relperm::LAYOUT_RELPERM > faceRelPerm1( 1, 1, 2 );
+ StackArray< real64, 4, 4, constitutive::relperm::LAYOUT_RELPERM_DS > dfacePhaseRelPerm1_dPhaseVolFrac( 1, 1, 2, 2 );
+ StackArray< real64, 3, 2, constitutive::relperm::LAYOUT_RELPERM > relPerm1( 1, 1, 2 );
+ StackArray< real64, 4, 4, constitutive::relperm::LAYOUT_RELPERM_DS > dPhaseRelPerm1_dPhaseVolFrac( 1, 1, 2, 2 );
+ StackArray< real64, 3, 2, constitutive::relperm::LAYOUT_RELPERM > faceRelPerm2( 1, 1, 2 );
+ StackArray< real64, 4, 4, constitutive::relperm::LAYOUT_RELPERM_DS > dfacePhaseRelPerm2_dPhaseVolFrac( 1, 1, 2, 2 );
+ StackArray< real64, 3, 2, constitutive::relperm::LAYOUT_RELPERM > relPerm2( 1, 1, 2 );
+ StackArray< real64, 4, 4, constitutive::relperm::LAYOUT_RELPERM_DS > dPhaseRelPerm2_dPhaseVolFrac( 1, 1, 2, 2 );
+
+
+ using T5 = std::decay_t< decltype(castedRelPerm1) >;
+ if constexpr (std::is_same_v< T5, constitutive::TableRelativePermeabilityHysteresis >) {
+ relPermWrapper1.compute( phaseVolFrac1[0],
+ phaseMaxHistoricalVolFraction1[0],
+ phaseMinHistoricalVolFraction1[0],
+ trappedVolFrac1[0][0],
+ relPerm1[0][0],
+ dPhaseRelPerm1_dPhaseVolFrac[0][0] );
+
+ }
+ else
+ {
+
+ relPermWrapper1.compute( phaseVolFrac1[0],
+ trappedVolFrac1[0][0],
+ relPerm1[0][0],
+ dPhaseRelPerm1_dPhaseVolFrac[0][0] );
+ }
+
+ using T6 = std::decay_t< decltype(castedRelPerm2) >;
+ if constexpr (std::is_same_v< T6, constitutive::TableRelativePermeabilityHysteresis >) {
+ relPermWrapper2.compute( phaseVolFrac2[0],
+ phaseMaxHistoricalVolFraction2[0],
+ phaseMinHistoricalVolFraction2[0],
+ trappedVolFrac2[0][0],
+ relPerm2[0][0],
+ dPhaseRelPerm2_dPhaseVolFrac[0][0] );
+
+ }
+ else
+ {
+
+ relPermWrapper2.compute( phaseVolFrac2[0],
+ trappedVolFrac2[0][0],
+ relPerm2[0][0],
+ dPhaseRelPerm2_dPhaseVolFrac[0][0] );
+ }
+
+
+ // Use of the fluid model kernel wrapper
+ StackArray< real64, 3, 2, constitutive::multifluid::LAYOUT_PHASE > phaseDensity1( 1, 1, 2 );
+ StackArray< real64, 3, 2, constitutive::multifluid::LAYOUT_PHASE > phaseViscosity1( 1, 1, 2 );
+ StackArray< real64, 4, 4, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseDens1_dP( 1, 1, 2, 2 );
+ StackArray< real64, 4, 4, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseVisc1_dP( 1, 1, 2, 2 );
+ StackArray< real64, 3, 2, constitutive::multifluid::LAYOUT_PHASE > phaseDensity2( 1, 1, 2 );
+ StackArray< real64, 3, 2, constitutive::multifluid::LAYOUT_PHASE > phaseViscosity2( 1, 1, 2 );
+ StackArray< real64, 4, 4, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseDens2_dP( 1, 1, 2, 2 );
+ StackArray< real64, 4, 4, constitutive::multifluid::LAYOUT_PHASE_DC > dPhaseVisc2_dP( 1, 1, 2, 2 );
+
+ // Declare the MultiFluidVar (PhaseProp) type
+ TwoPhaseImmiscibleFluid::PhaseProp phaseDensity_temp1;
+ TwoPhaseImmiscibleFluid::PhaseProp phaseViscosity_temp1;
+ phaseDensity_temp1.value.resize( 1, 1, 2 ); // or whatever sizes you need
+ phaseDensity_temp1.derivs.resize( 1, 1, 2, 2 ); // make sure all dims > 0
+ phaseViscosity_temp1.value.resize( 1, 1, 2 ); // or whatever sizes you need
+ phaseViscosity_temp1.derivs.resize( 1, 1, 2, 2 ); // make sure all dims > 0
+
+ auto phaseDensitySlice0 = TwoPhaseImmiscibleFluid::PhaseProp::SliceType(
+ phaseDensity_temp1.value[0][0], phaseDensity_temp1.derivs[0][0] );
+ auto phaseViscositySlice0 = TwoPhaseImmiscibleFluid::PhaseProp::SliceType(
+ phaseViscosity_temp1.value[0][0], phaseViscosity_temp1.derivs[0][0] );
+ fluidWrapper1.compute( pressures[0], phaseDensitySlice0, phaseViscositySlice0 );
+
+ // Temporary:
+ phaseDensity1[0][0][0] = phaseDensitySlice0.value[0];
+ phaseDensity1[0][0][1] = phaseDensitySlice0.value[1];
+ dPhaseDens1_dP[0][0][0][0] = phaseDensitySlice0.derivs[0][0];
+ dPhaseDens1_dP[0][0][0][1] = 0;
+ dPhaseDens1_dP[0][0][1][0] = phaseDensitySlice0.derivs[1][0];
+ dPhaseDens1_dP[0][0][1][1] = 0;
+
+ phaseViscosity1[0][0][0] = phaseViscositySlice0.value[0];
+ phaseViscosity1[0][0][1] = phaseViscositySlice0.value[1];
+ dPhaseVisc1_dP[0][0][0][0] = phaseViscositySlice0.derivs[0][0];
+ dPhaseVisc1_dP[0][0][0][1] = 0;
+ dPhaseVisc1_dP[0][0][1][0] = phaseViscositySlice0.derivs[1][0];
+ dPhaseVisc1_dP[0][0][1][1] = 0;
+
+ auto phaseDensitySlice1 = TwoPhaseImmiscibleFluid::PhaseProp::SliceType(
+ phaseDensity_temp1.value[0][0], phaseDensity_temp1.derivs[0][0] );
+ auto phaseViscositySlice1 = TwoPhaseImmiscibleFluid::PhaseProp::SliceType(
+ phaseViscosity_temp1.value[0][0], phaseViscosity_temp1.derivs[0][0] );
+ fluidWrapper2.compute( pressures[1], phaseDensitySlice1, phaseViscositySlice1 );
+
+
+ phaseDensity2[0][0][0] = phaseDensitySlice1.value[0];
+ phaseDensity2[0][0][1] = phaseDensitySlice1.value[1];
+ dPhaseDens2_dP[0][0][0][0] = phaseDensitySlice1.derivs[0][0];
+ dPhaseDens2_dP[0][0][0][1] = 0;
+ dPhaseDens2_dP[0][0][1][0] = phaseDensitySlice1.derivs[1][0];
+ dPhaseDens2_dP[0][0][1][1] = 0;
+
+ phaseViscosity2[0][0][0] = phaseViscositySlice1.value[0];
+ phaseViscosity2[0][0][1] = phaseViscositySlice1.value[1];
+ dPhaseVisc2_dP[0][0][0][0] = phaseViscositySlice1.derivs[0][0];
+ dPhaseVisc2_dP[0][0][0][1] = 0;
+ dPhaseVisc2_dP[0][0][1][0] = phaseViscositySlice1.derivs[1][0];
+ dPhaseVisc2_dP[0][0][1][1] = 0;
+
+ // clear working arrays
+ real64 halfFluxVal[2][2]{};
+ real64 dhalfFlux1_dP[2][2]{};
+ real64 dhalfFlux1_dS[2][2]{};
+ real64 dhalfFlux2_dP[2][2]{};
+ real64 dhalfFlux2_dS[2][2]{};
+ real64 dhalfFlux_duT[2][2]{};
+ real64 dhalfFlux_dpc[2][2]{};
+
+ //new
+ real64 fluxVal[2]{};
+ real64 dFlux_dP[2][2]{};
+ real64 dFlux_dS[2][2]{};
+
+ real64 duT_dP[2]{};
+ real64 duT_dS[2]{};
+
+ duT_dP[0] = cellCenterDuT[0];
+ duT_dP[1] = cellCenterDuT[1];
+
+ duT_dS[0] = cellCenterDuT[2];
+ duT_dS[1] = cellCenterDuT[3];
+
+ // initial guess:
+
+ real64 const Pc1 = capPres1[0][0][0];
+ real64 const Pc2 = capPres2[0][0][0];
+
+ real64 Pc_union_min = fmin( Pc1_min, Pc2_min );
+ real64 Pc_union_max = fmax( Pc1_max, Pc2_max );
+
+ real64 Pc_min_all = fmax( Pc1_min, Pc2_min );
+ real64 Pc_max_all = fmin( Pc1_max, Pc2_max );
+ bool rangesOverlap = Pc_min_all < Pc_max_all;
+
+ real64 Pc_bracket_lo = Pc_union_min;
+ real64 Pc_bracket_hi = Pc_union_max;
+ real64 res_bracket_lo = 0.0;
+ real64 res_bracket_hi = 0.0;
+ bool bracket_lo_set = false;
+ bool bracket_hi_set = false;
+
+ constexpr bool ENABLE_WARM_START = true;
+ real64 Pc_int;
+ bool usedWarmStart = false;
+ if( ENABLE_WARM_START && warmStartPc > 0.0 )
+ {
+ Pc_int = warmStartPc;
+ usedWarmStart = true;
+ }
+ else
+ {
+ Pc_int = rangesOverlap ? ( Pc_min_all + Pc_max_all ) / 2.0
+ : LvArray::math::max( Pc1, Pc2 );
+ }
+ Pc_int = fmin( Pc_union_max, fmax( Pc_int, Pc_union_min ) );
+
+ real64 Pc_int_iterate = Pc_int;
+
+ int iter = 0;
+ int div = 0;
+
+ int n_same_pc = 0;
+ real64 prev_Pc_evaluated = -1.0e30;
+ int stuck_probe_level = 0;
+
+ constexpr bool ENABLE_BEST_SOLUTION_FALLBACK = false;
+ constexpr real64 FALLBACK_TOL_FACTOR = 100.0;
+ real64 best_Pc = 0.0;
+ real64 best_absRes = 1.0e30;
+ bool fallback_used = false;
+
+ constexpr bool ENABLE_SWEEP_FALLBACK = true;
+ constexpr real64 SWEEP_DS = 0.005;
+ constexpr integer SWEEP_MIN_POINTS = 100;
+ constexpr real64 SWEEP_ACCEPT_TOL_FACTOR = 100.0;
+ bool sweep_active = false;
+ real64 sweep_best_Pc = 0.0;
+ real64 sweep_best_absRes = 1.0e30;
+ int sweep_newton_iter_end = 0;
+
+ real64 last_local_residual = 0.0;
+ real64 last_local_jacobian = 0.0;
+ real64 last_facePhaseVolFrac1_0 = 0.0;
+ real64 last_facePhaseVolFrac2_0 = 0.0;
+ real64 last_faceCapPres1 = 0.0;
+ real64 last_faceCapPres2 = 0.0;
+ integer last_iter = 0;
+
+ while( iter < max_iter )
+ {
+
+ Pc_int_iterate = Pc_int;
+
+ constexpr bool ENABLE_INITIAL_SAT_DEBUG = false;
+ if constexpr (ENABLE_INITIAL_SAT_DEBUG) {
+ if( iter == 0 )
+ {
+ std::cout << "[INITIAL_SAT_DEBUG] Local solver iter=" << iter << ", Initial S1=" << phaseVolFrac1[0][0]
+ << ", Initial S2=" << phaseVolFrac2[0][0] << std::endl;
+ std::cout << "[INITIAL_SAT_DEBUG] Initial Pc1=" << capPres1[0][0][0]
+ << ", Initial Pc2=" << capPres2[0][0][0] << std::endl;
+ }
+ }
+
+ // clear working arrays
+ real64 density[2]{};
+ real64 dDens_dP[2][2]{};
+ real64 gravityCof[2]{};
+ real64 viscosity[2]{};
+ real64 dVisc_dP[2][2]{};
+
+ real64 viscous[2][2]{};
+ real64 bouyancy[2][2]{};
+ real64 capillarity[2][2]{};
+
+ real64 dV1_dS[2][2]{};
+ real64 dG1_dS[2][2]{};
+ real64 dC1_dS[2][2]{};
+ real64 dV2_dS[2][2]{};
+ real64 dG2_dS[2][2]{};
+ real64 dC2_dS[2][2]{};
+ real64 dV1_dpc[2][2]{};
+ real64 dG1_dpc[2][2]{};
+ real64 dC1_dpc[2][2]{};
+ real64 dV2_dpc[2][2]{};
+ real64 dG2_dpc[2][2]{};
+ real64 dC2_dpc[2][2]{};
+
+ real64 local_residual = 0;
+ real64 local_jacobian = 0;
+
+ {
+ bool bracketReady = bracket_lo_set && bracket_hi_set;
+ real64 clamp_lo = bracketReady ? Pc_bracket_lo : Pc_union_min;
+ real64 clamp_hi = bracketReady ? Pc_bracket_hi : Pc_union_max;
+ Pc_int = fmin( clamp_hi, fmax( Pc_int, clamp_lo ) );
+ }
+
+ faceCapPres1[0][0][0] = fmin( Pc1_max, Pc_int );
+ faceCapPres2[0][0][0] = fmin( Pc2_max, Pc_int );
+ bool const faceCapPres1_clamped = (faceCapPres1[0][0][0] < Pc_int - 1e-10);
+ bool const faceCapPres2_clamped = (faceCapPres2[0][0][0] < Pc_int - 1e-10);
+
+ JFunc1[0] = JFMultipliers[0];
+ JFunc2[0] = JFMultipliers[1];
+
+ constexpr bool ENABLE_TCH_COMPUTEINV_DEBUG = false;
+ constexpr bool ENABLE_TCH_COMPUTE_DEBUG = false;
+
+ using T3 = std::decay_t< decltype(castedCapPres1) >;
+ if constexpr (std::is_same_v< T3, JFunctionCapillaryPressure >) {
+ capPresWrapper1.computeInv( facePhaseVolFrac1[0],
+ JFunc1.toSliceConst(),
+ faceCapPres1[0][0],
+ dfacePhaseVolFrac_dCapPres1[0][0] );
+ facePhaseVolFrac1[0][0] = fmin( 1.0, fmax( facePhaseVolFrac1[0][0], 0.0 ));
+ facePhaseVolFrac1[0][1] = fmin( 1.0, fmax( facePhaseVolFrac1[0][1], 0.0 ));
+ //get derivatives:
+ capPresWrapper1.compute( facePhaseVolFrac1[0],
+ JFunc1.toSliceConst(),
+ faceCapPres1[0][0],
+ dCapPres1_dfacePhaseVolFrac[0][0] );
+
+ }
+ else if constexpr (std::is_same_v< T3, TableCapillaryPressureHysteresis >) {
+ if constexpr (ENABLE_TCH_COMPUTEINV_DEBUG) {
+ if( iter < 5 || iter % 10 == 0 || iter >= max_iter - 5 )
+ {
+ std::cout << "[TCH_COMPUTEINV_DEBUG] Cell1, iter=" << iter << std::endl;
+ std::cout << " BEFORE computeInv: Pc=" << faceCapPres1[0][0][0]
+ << ", S=" << facePhaseVolFrac1[0][0]
+ << ", mode=" << modes[0] << std::endl;
+ std::cout << " phaseMaxHistoricalVolFraction1[0][0]=" << phaseMaxHistoricalVolFraction1[0][0]
+ << ", phaseMinHistoricalVolFraction1[0][0]=" << phaseMinHistoricalVolFraction1[0][0] << std::endl;
+ }
+ }
+
+ auto tempMode0 = modes[0];
+ capPresWrapper1.computeInv( facePhaseVolFrac1[0],
+ phaseMaxHistoricalVolFraction1[0],
+ phaseMinHistoricalVolFraction1[0],
+ phaseMode2PeakSlice1,
+ faceTrappedVolFrac1[0][0],
+ faceCapPres1[0][0],
+ dfacePhaseVolFrac_dCapPres1[0][0],
+ tempMode0 );
+ real64 dS_dPc_after_computeInv_TCH = dfacePhaseVolFrac_dCapPres1[0][0][0][0];
+ facePhaseVolFrac1[0][0] = fmin( 1.0, fmax( facePhaseVolFrac1[0][0], 0.0 ));
+ facePhaseVolFrac1[0][1] = fmin( 1.0, fmax( facePhaseVolFrac1[0][1], 0.0 ));
+
+ if constexpr (ENABLE_TCH_COMPUTEINV_DEBUG) {
+ if( iter < 5 || iter % 10 == 0 || iter >= max_iter - 5 )
+ {
+ std::cout << " AFTER computeInv: Pc=" << faceCapPres1[0][0][0]
+ << ", S=" << facePhaseVolFrac1[0][0]
+ << ", dS_dPc=" << dS_dPc_after_computeInv_TCH << std::endl;
+ }
+ }
+
+ real64 Pc_before_compute_TCH = faceCapPres1[0][0][0];
+ if( modes[0] == fields::cappres::ModeIndexType::DRAINAGE ||
+ modes[0] == fields::cappres::ModeIndexType::IMBIBITION )
+ {
+ real64 rawPc = 0.0, rawDPcDS = 0.0;
+ capPresWrapper1.computeRawTablePc( static_cast< integer >( modes[0] ),
+ facePhaseVolFrac1[0][0],
+ rawPc, rawDPcDS );
+ faceCapPres1[0][0][0] = rawPc;
+ dCapPres1_dfacePhaseVolFrac[0][0][0][0] = rawDPcDS;
+ }
+ else
+ {
+ auto tempComputeMode0 = modes[0];
+ capPresWrapper1.compute( facePhaseVolFrac1[0],
+ phaseMaxHistoricalVolFraction1[0],
+ phaseMinHistoricalVolFraction1[0],
+ faceTrappedVolFrac1[0][0],
+ faceCapPres1[0][0],
+ dCapPres1_dfacePhaseVolFrac[0][0],
+ tempComputeMode0,
+ phaseMode2PeakSlice1 );
+ }
+ real64 dPc_dS_after_compute_TCH = dCapPres1_dfacePhaseVolFrac[0][0][0][0];
+
+ if constexpr (ENABLE_TCH_COMPUTE_DEBUG) {
+ if( iter < 5 || iter % 10 == 0 || iter >= max_iter - 5 )
+ {
+ std::cout << "[TCH_COMPUTE_DEBUG] Cell1, iter=" << iter << std::endl;
+ std::cout << " BEFORE compute: Pc=" << Pc_before_compute_TCH
+ << ", S=" << facePhaseVolFrac1[0][0] << std::endl;
+ std::cout << " AFTER compute: Pc=" << faceCapPres1[0][0][0]
+ << ", dPc_dS=" << dPc_dS_after_compute_TCH << std::endl;
+ std::cout << " Pc change=" << (faceCapPres1[0][0][0] - Pc_before_compute_TCH) << std::endl;
+ real64 product = dS_dPc_after_computeInv_TCH * dPc_dS_after_compute_TCH;
+ std::cout << " dS_dPc * dPc_dS = " << product
+ << " (should be ~1.0, error=" << std::abs( product - 1.0 ) << ")" << std::endl;
+ }
+ }
+
+ }
+ else
+ {
+ capPresWrapper1.computeInv( facePhaseVolFrac1[0],
+ faceCapPres1[0][0],
+ dfacePhaseVolFrac_dCapPres1[0][0] );
+ real64 dS_dPc_after_computeInv_TCP = dfacePhaseVolFrac_dCapPres1[0][0][0][0];
+ facePhaseVolFrac1[0][0] = fmin( 1.0, fmax( facePhaseVolFrac1[0][0], 0.0 ));
+ facePhaseVolFrac1[0][1] = fmin( 1.0, fmax( facePhaseVolFrac1[0][1], 0.0 ));
+ //get derivatives:
+ real64 Pc_before_compute_TCP = faceCapPres1[0][0][0];
+ real64 dPc_dS_before_TCP = dCapPres1_dfacePhaseVolFrac[0][0][0][0];
+ capPresWrapper1.compute( facePhaseVolFrac1[0],
+ faceCapPres1[0][0],
+ dCapPres1_dfacePhaseVolFrac[0][0] );
+ real64 dPc_dS_after_compute_TCP = dCapPres1_dfacePhaseVolFrac[0][0][0][0];
+ constexpr bool ENABLE_COMPUTE_DEBUG = false;
+ if constexpr (ENABLE_COMPUTE_DEBUG) {
+ std::cout << "[COMPUTE_DEBUG_TCP] After computeInv(): dS_dPc=" << dS_dPc_after_computeInv_TCP
+ << ", S=" << facePhaseVolFrac1[0][0] << ", Pc=" << faceCapPres1[0][0][0] << std::endl;
+ std::cout << "[COMPUTE_DEBUG_TCP] After compute(): Pc_before=" << Pc_before_compute_TCP
+ << ", Pc_after=" << faceCapPres1[0][0][0]
+ << ", dPc_dS_before=" << dPc_dS_before_TCP
+ << ", dPc_dS_after=" << dPc_dS_after_compute_TCP
+ << ", S=" << facePhaseVolFrac1[0][0] << std::endl;
+ real64 product = dS_dPc_after_computeInv_TCP * dPc_dS_after_compute_TCP;
+ std::cout << "[COMPUTE_DEBUG_TCP] dS_dPc * dPc_dS = " << product
+ << " (should be ~1.0, error=" << std::abs( product - 1.0 ) << ")" << std::endl;
+ real64 Pc_diff = faceCapPres1[0][0][0] - Pc_before_compute_TCP;
+ std::cout << "[COMPUTE_DEBUG_TCP] Pc change after compute() = " << Pc_diff
+ << " (should be ~0.0)" << std::endl;
+ }
+ }
+
+ if( faceCapPres1_clamped )
+ {
+ dfacePhaseVolFrac_dCapPres1[0][0][0][0] = 0.0;
+ }
+
+ using T4 = std::decay_t< decltype(castedCapPres2) >;
+ if constexpr (std::is_same_v< T4, JFunctionCapillaryPressure >) {
+ // evaluating cell-center Pc:
+ capPresWrapper2.computeInv( facePhaseVolFrac2[0],
+ JFunc2.toSliceConst(),
+ faceCapPres2[0][0],
+ dfacePhaseVolFrac_dCapPres2[0][0] );
+ facePhaseVolFrac2[0][0] = fmin( 1.0, fmax( facePhaseVolFrac2[0][0], 0.0 ));
+ facePhaseVolFrac2[0][1] = fmin( 1.0, fmax( facePhaseVolFrac2[0][1], 0.0 ));
+
+//get derivatives:
+
+ capPresWrapper2.compute( facePhaseVolFrac2[0],
+ JFunc2.toSliceConst(),
+ faceCapPres2[0][0],
+ dCapPres2_dfacePhaseVolFrac[0][0] );
+
+ }
+ else if constexpr (std::is_same_v< T4, TableCapillaryPressureHysteresis >) {
+ if constexpr (ENABLE_TCH_COMPUTEINV_DEBUG) {
+ if( iter < 5 || iter % 10 == 0 || iter >= max_iter - 5 )
+ {
+ std::cout << "[TCH_COMPUTEINV_DEBUG] Cell2, iter=" << iter << std::endl;
+ std::cout << " BEFORE computeInv: Pc=" << faceCapPres2[0][0][0]
+ << ", S=" << facePhaseVolFrac2[0][0]
+ << ", mode=" << modes[1] << std::endl;
+ std::cout << " phaseMaxHistoricalVolFraction2[0][0]=" << phaseMaxHistoricalVolFraction2[0][0]
+ << ", phaseMinHistoricalVolFraction2[0][0]=" << phaseMinHistoricalVolFraction2[0][0] << std::endl;
+ }
+ }
+
+ auto tempMode1 = modes[1];
+ capPresWrapper2.computeInv( facePhaseVolFrac2[0],
+ phaseMaxHistoricalVolFraction2[0],
+ phaseMinHistoricalVolFraction2[0],
+ phaseMode2PeakSlice2,
+ faceTrappedVolFrac2[0][0],
+ faceCapPres2[0][0],
+ dfacePhaseVolFrac_dCapPres2[0][0],
+ tempMode1 );
+ facePhaseVolFrac2[0][0] = fmin( 1.0, fmax( facePhaseVolFrac2[0][0], 0.0 ));
+ facePhaseVolFrac2[0][1] = fmin( 1.0, fmax( facePhaseVolFrac2[0][1], 0.0 ));
+ real64 dS_dPc_after_computeInv_TCH2 = dfacePhaseVolFrac_dCapPres2[0][0][0][0];
+
+ if constexpr (ENABLE_TCH_COMPUTEINV_DEBUG) {
+ if( iter < 5 || iter % 10 == 0 || iter >= max_iter - 5 )
+ {
+ std::cout << " AFTER computeInv: Pc=" << faceCapPres2[0][0][0]
+ << ", S=" << facePhaseVolFrac2[0][0]
+ << ", dS_dPc=" << dS_dPc_after_computeInv_TCH2 << std::endl;
+ }
+ }
+
+ real64 Pc_before_compute_TCH2 = faceCapPres2[0][0][0];
+
+ if( modes[1] == fields::cappres::ModeIndexType::DRAINAGE ||
+ modes[1] == fields::cappres::ModeIndexType::IMBIBITION )
+ {
+ real64 rawPc2 = 0.0, rawDPcDS2 = 0.0;
+ capPresWrapper2.computeRawTablePc( static_cast< integer >( modes[1] ),
+ facePhaseVolFrac2[0][0],
+ rawPc2, rawDPcDS2 );
+ faceCapPres2[0][0][0] = rawPc2;
+ dCapPres2_dfacePhaseVolFrac[0][0][0][0] = rawDPcDS2;
+ }
+ else
+ {
+ auto tempComputeMode1 = modes[1];
+ capPresWrapper2.compute( facePhaseVolFrac2[0],
+ phaseMaxHistoricalVolFraction2[0],
+ phaseMinHistoricalVolFraction2[0],
+ faceTrappedVolFrac2[0][0],
+ faceCapPres2[0][0],
+ dCapPres2_dfacePhaseVolFrac[0][0],
+ tempComputeMode1,
+ phaseMode2PeakSlice2 );
+ }
+
+ if constexpr (ENABLE_TCH_COMPUTE_DEBUG) {
+ if( iter < 5 || iter % 10 == 0 || iter >= max_iter - 5 )
+ {
+ std::cout << "[TCH_COMPUTE_DEBUG] Cell2, iter=" << iter << std::endl;
+ std::cout << " BEFORE compute: Pc=" << Pc_before_compute_TCH2
+ << ", S=" << facePhaseVolFrac2[0][0] << std::endl;
+ std::cout << " AFTER compute: Pc=" << faceCapPres2[0][0][0]
+ << ", dPc_dS=" << dCapPres2_dfacePhaseVolFrac[0][0][0] << std::endl;
+ std::cout << " Pc change=" << (faceCapPres2[0][0][0] - Pc_before_compute_TCH2) << std::endl;
+ real64 dPc_dS_after_compute_TCH2 = dCapPres2_dfacePhaseVolFrac[0][0][0][0];
+ real64 product = dS_dPc_after_computeInv_TCH2 * dPc_dS_after_compute_TCH2;
+ std::cout << " dS_dPc * dPc_dS = " << product
+ << " (should be ~1.0, error=" << std::abs( product - 1.0 ) << ")" << std::endl;
+ }
+ }
+
+ }
+ else
+ {
+ // evaluating cell-center Pc:
+ capPresWrapper2.computeInv( facePhaseVolFrac2[0],
+ faceCapPres2[0][0],
+ dfacePhaseVolFrac_dCapPres2[0][0] );
+ facePhaseVolFrac2[0][0] = fmin( 1.0, fmax( facePhaseVolFrac2[0][0], 0.0 ));
+ facePhaseVolFrac2[0][1] = fmin( 1.0, fmax( facePhaseVolFrac2[0][1], 0.0 ));
+
+//get derivatives:
+
+ real64 Pc_before_compute_TCP2 = faceCapPres2[0][0][0];
+ capPresWrapper2.compute( facePhaseVolFrac2[0],
+ faceCapPres2[0][0],
+ dCapPres2_dfacePhaseVolFrac[0][0] );
+ constexpr bool ENABLE_COMPUTE_DEBUG = false;
+ if constexpr (ENABLE_COMPUTE_DEBUG) {
+ std::cout << "[COMPUTE_DEBUG_TCP] After compute() cell2: Pc_before=" << Pc_before_compute_TCP2
+ << ", Pc_after=" << faceCapPres2[0][0][0]
+ << ", dPc_dS=" << dCapPres2_dfacePhaseVolFrac[0][0][0]
+ << ", S=" << facePhaseVolFrac2[0][0] << std::endl;
+ }
+ }
+
+ if( faceCapPres2_clamped )
+ {
+ dfacePhaseVolFrac_dCapPres2[0][0][0][0] = 0.0;
+ }
+
+ // compute relative permeability for both faces:
+
+ using T7 = std::decay_t< decltype(castedRelPerm1) >;
+ if constexpr (std::is_same_v< T7, constitutive::TableRelativePermeabilityHysteresis >) {
+
+ relPermWrapper1.compute( facePhaseVolFrac1[0],
+ phaseMaxHistoricalVolFraction1[0],
+ phaseMinHistoricalVolFraction1[0],
+ faceTrappedVolFrac1[0][0],
+ faceRelPerm1[0][0],
+ dfacePhaseRelPerm1_dPhaseVolFrac[0][0] );
+
+ }
+ else
+ {
+
+ relPermWrapper1.compute( facePhaseVolFrac1[0],
+ faceTrappedVolFrac1[0][0],
+ faceRelPerm1[0][0],
+ dfacePhaseRelPerm1_dPhaseVolFrac[0][0] );
+ }
+
+ constexpr bool ENABLE_RELPERM_DEBUG = false;
+ if constexpr (ENABLE_RELPERM_DEBUG) {
+ if( iter == 0 )
+ {
+ std::cout << "[RELPERM_DEBUG] After relPerm1 compute: S1_face=" << facePhaseVolFrac1[0][0]
+ << ", faceRelPerm1[0][0][0]=" << faceRelPerm1[0][0][0]
+ << ", faceRelPerm1[0][0][1]=" << faceRelPerm1[0][0][1] << std::endl;
+ std::cout << "[RELPERM_DEBUG] dfacePhaseRelPerm1_dPhaseVolFrac[0][0][0][0]="
+ << dfacePhaseRelPerm1_dPhaseVolFrac[0][0][0][0]
+ << ", dfacePhaseRelPerm1_dPhaseVolFrac[0][0][1][1]="
+ << dfacePhaseRelPerm1_dPhaseVolFrac[0][0][1][1] << std::endl;
+ }
+ }
+
+ using T8 = std::decay_t< decltype(castedRelPerm2) >;
+ if constexpr (std::is_same_v< T8, constitutive::TableRelativePermeabilityHysteresis >) {
+
+ relPermWrapper2.compute( facePhaseVolFrac2[0],
+ phaseMaxHistoricalVolFraction2[0],
+ phaseMinHistoricalVolFraction2[0],
+ faceTrappedVolFrac2[0][0],
+ faceRelPerm2[0][0],
+ dfacePhaseRelPerm2_dPhaseVolFrac[0][0] );
+
+ }
+ else
+ {
+
+ relPermWrapper2.compute( facePhaseVolFrac2[0],
+ faceTrappedVolFrac2[0][0],
+ faceRelPerm2[0][0],
+ dfacePhaseRelPerm2_dPhaseVolFrac[0][0] );
+ }
+
+ if constexpr (ENABLE_RELPERM_DEBUG) {
+ if( iter == 0 )
+ {
+ std::cout << "[RELPERM_DEBUG] After relPerm2 compute: S2_face=" << facePhaseVolFrac2[0][0]
+ << ", faceRelPerm2[0][0][0]=" << faceRelPerm2[0][0][0]
+ << ", faceRelPerm2[0][0][1]=" << faceRelPerm2[0][0][1] << std::endl;
+ std::cout << "[RELPERM_DEBUG] dfacePhaseRelPerm2_dPhaseVolFrac[0][0][0][0]="
+ << dfacePhaseRelPerm2_dPhaseVolFrac[0][0][0][0]
+ << ", dfacePhaseRelPerm2_dPhaseVolFrac[0][0][1][1]="
+ << dfacePhaseRelPerm2_dPhaseVolFrac[0][0][1][1] << std::endl;
+ }
+ }
+
+
+ bool check = false;
+ bool k_up_0_w = 1;
+ bool k_up_1_w = 1;
+ bool k_up_0_n = 1;
+ bool k_up_1_n = 1;
+
+ if( uT < 0.0 )
+ {
+ k_up_0_w = 0;
+ k_up_1_w = 0;
+ k_up_0_n = 0;
+ k_up_1_n = 0;
+ }
+
+ if( std::fabs( uT ) < 1e-20 )
+ {
+ k_up_0_w = 1;
+ k_up_1_w = 1;
+ k_up_0_n = 0;
+ k_up_1_n = 0;
+ }
+
+
+ localIndex k_up_0[2] = {static_cast< localIndex >(!k_up_0_w), static_cast< localIndex >(!k_up_0_n)};
+ localIndex k_up_1[2] = {static_cast< localIndex >(k_up_1_w), static_cast< localIndex >(k_up_1_n)};
+ bool k_up_0_check[2] = {false, false};
+ bool k_up_1_check[2] = {false, false};
+
+ while( !check )
+ {
+ k_up_0_check[0] = false;
+ k_up_0_check[1] = false;
+ k_up_1_check[0] = false;
+ k_up_1_check[1] = false;
+ for( integer ix = 0; ix < 2; ++ix ) // for loop over each half flux
+ {
+
+ // clear working arrays for each half flux:
+ real64 densMean[2]{};
+ real64 dDensMean_dP[2][2]{};
+
+ real64 presGrad[2]{};
+ real64 dPresGrad_dP[2][2]{};
+
+ real64 gravHead[2]{};
+ real64 dGravHead_dP[2][2]{};
+
+ real64 capGrad[2]{};
+ // real64 capPresIC[2][2]{};
+ // real64 jFMultiplier[2][2]{};
+ real64 dCapGrad_dP[2][2]{};
+ real64 dCapGrad_dS[2][2]{};
+
+ real64 mobility[2]{};
+ real64 dMob_dP[2][2]{};
+ real64 dMob_dS[2][2]{};
+
+ real64 total_mobility = 0;
+ gravityCof[0] = 0;
+ gravityCof[1] = 0;
+
+ for( integer ip = 0; ip < 2; ++ip ) // loop over phases
+ {
+ // calculate quantities on primary connected cells
+ if( ix == 0 )
+ {
+ density[ip] = phaseDensity1[0][0][ip];
+ dDens_dP[ip][ix] = dPhaseDens1_dP[0][0][ip][ip];
+
+ viscosity[ip] = phaseViscosity1[0][0][ip];
+ dVisc_dP[ip][ix] = dPhaseVisc1_dP[0][0][ip][ip];
+ }
+ else
+ {
+ density[ip] = phaseDensity2[0][0][ip];
+ dDens_dP[ip][ix] = dPhaseDens2_dP[0][0][ip][ip];
+
+ viscosity[ip] = phaseViscosity2[0][0][ip];
+ dVisc_dP[ip][ix] = dPhaseVisc2_dP[0][0][ip][ip];
+ }
+
+ densMean[ip] = density[ip];
+ dDensMean_dP[ip][0] = dDens_dP[ip][ix];
+ dDensMean_dP[ip][1] = dDens_dP[ip][ix];
+
+ //***** calculation of flux *****
+
+ // compute potential difference
+ real64 potScale = 0.0;
+ real64 dPresGrad_dTrans = 0.0;
+ real64 dGravHead_dTrans = 0.0;
+ real64 dCapGrad_dTrans = 0.0;
+ constexpr int signPotDiff[2] = {1, -1};
+ constexpr int signTix[2] = {1, -1};
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+
+ real64 const pressure = pressures[ix];
+ presGrad[ip] += signTix[ke] * transHat[ix] * pressure;
+ dPresGrad_dTrans += signPotDiff[ke] * pressure;
+ dPresGrad_dP[ip][ke] = signTix[ke] * transHat[ix];
+
+ real64 gravD = 0.0;
+
+ if( ke == 0 )
+ {
+ gravD += signTix[ke] * transHat[ix] * gravCoef[ix];
+ }
+ else
+ {
+ gravD += signTix[ke] * transHat[ix] * gravCoefHat[ix];
+ }
+
+ real64 pot = signTix[ke] * transHat[ix] * pressure - densMean[ip] * gravD;
+
+ gravHead[ip] += densMean[ip] * gravD;
+ gravityCof[ip] += gravD;
+
+ dGravHead_dTrans += signPotDiff[ke] * densMean[ip] * gravCoefHat[ix];
+
+ for( integer i = 0; i < 2; ++i )
+ {
+ dGravHead_dP[ip][i] += dDensMean_dP[ip][i] * gravD;
+ }
+
+ real64 capPres = capPres1[0][0][ip];
+
+ if( ke == 1 && ix == 0 )
+ {
+ capPres = faceCapPres1[0][0][ip];
+ }
+ else if( ke == 1 && ix == 1 )
+ {
+ capPres = faceCapPres2[0][0][ip];
+ }
+ else if( ke == 0 && ix == 1 )
+ {
+
+ capPres = capPres2[0][0][ip];
+ }
+
+ dCapGrad_dTrans -= signPotDiff[ke] * capPres;
+ pot -= signTix[ke] * transHat[ix] * capPres;
+
+ capGrad[ip] -= signTix[ke] * transHat[ix] * capPres;
+
+ potScale = fmax( potScale, fabs( pot ) );
+ }
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ dPresGrad_dP[ip][ke] += signTix[ke] * dTransHat_dP[ix] * dPresGrad_dTrans;
+
+ dGravHead_dP[ip][ke] += signTix[ke] * dTransHat_dP[ix] * dGravHead_dTrans;
+
+ real64 dCapPres_dS = dCapPres1_dPhaseVolFrac[0][0][ip][ip];
+
+ if( ke == 1 && ix == 0 )
+ {
+ dCapPres_dS = dCapPres1_dfacePhaseVolFrac[0][0][ip][ip];
+ }
+ else if( ke == 1 && ix == 1 )
+ {
+ dCapPres_dS = dCapPres2_dfacePhaseVolFrac[0][0][ip][ip];
+ }
+ else if( ke == 0 && ix == 1 )
+ {
+ dCapPres_dS = dCapPres2_dPhaseVolFrac[0][0][ip][ip];
+ }
+
+ constexpr bool ENABLE_DCAPPRES_DS_DEBUG = false;
+ if constexpr (ENABLE_DCAPPRES_DS_DEBUG) {
+ if( iter == 0 && ix == 0 && ip == 0 && ke == 0 )
+ {
+ std::cout << "[DCAPPRES_DS_DEBUG] iter=" << iter << ", ix=" << ix << ", ip=" << ip << ", ke=" << ke << std::endl;
+ std::cout << "[DCAPPRES_DS_DEBUG] dCapPres_dS=" << dCapPres_dS << " (from cell " << (ke+1) << ")" << std::endl;
+ std::cout << "[DCAPPRES_DS_DEBUG] dCapPres1_dfacePhaseVolFrac[0][0][0][0]=" << dCapPres1_dfacePhaseVolFrac[0][0][0][0] << std::endl;
+ std::cout << "[DCAPPRES_DS_DEBUG] dCapPres2_dfacePhaseVolFrac[0][0][0][0]=" << dCapPres2_dfacePhaseVolFrac[0][0][0][0] << std::endl;
+ }
+ }
+
+ dCapGrad_dP[ip][ke] += signTix[ke] * dTransHat_dP[ix] * dCapGrad_dTrans;
+ dCapGrad_dS[ip][ke] -= signTix[ke] * transHat[ix] * dCapPres_dS;
+ }
+
+ // *** upwinding ***
+ // compute potential gradient
+ real64 potGrad = presGrad[ip] - gravHead[ip];
+
+ potGrad += capGrad[ip];
+
+ // choose upstream cell
+ constexpr int sign[2] = {1, -1};
+
+ constexpr bool ENABLE_UPWIND_DEBUG = false;
+ if constexpr (ENABLE_UPWIND_DEBUG) {
+ if( iter == 0 && ip == 0 )
+ {
+ std::cout << "[UPWIND_DEBUG] iter=" << iter << ", ip=" << ip << ", ix=" << ix << ", k_up_0[ip]=" << k_up_0[ip] << ", k_up_1[ip]=" << k_up_1[ip] << std::endl;
+ std::cout << "[UPWIND_DEBUG] potGrad=" << potGrad << ", capGrad[ip]=" << capGrad[ip] << std::endl;
+ std::cout << "[UPWIND_DEBUG] dfacePhaseRelPerm1_dPhaseVolFrac[0][0][ip][ip]=" << dfacePhaseRelPerm1_dPhaseVolFrac[0][0][ip][ip] << std::endl;
+ std::cout << "[UPWIND_DEBUG] dPhaseRelPerm1_dPhaseVolFrac[0][0][ip][ip]=" << dPhaseRelPerm1_dPhaseVolFrac[0][0][ip][ip] << std::endl;
+ }
+ }
+
+ if( k_up_0[ip] == 1 && ix == 0 )
+ {
+ mobility[ip] = faceRelPerm1[0][0][ip] / viscosity[ip];
+ dMob_dP[ip][k_up_0[ip]] = mobility[ip] * (-dVisc_dP[ip][ix] / viscosity[ip]);
+
+ dMob_dS[ip][k_up_0[ip]] = sign[ip] * dfacePhaseRelPerm1_dPhaseVolFrac[0][0][ip][ip] / viscosity[ip];
+ if constexpr (ENABLE_UPWIND_DEBUG) {
+ if( iter == 0 && ip == 0 )
+ {
+ std::cout << "[UPWIND_DEBUG] Branch: k_up_0[ip]==1 && ix==0" << std::endl;
+ std::cout << "[UPWIND_DEBUG] dMob_dS[ip][k_up_0[ip]]=" << dMob_dS[ip][k_up_0[ip]] << ", ix=" << ix << std::endl;
+ }
+ }
+ }
+ else if( k_up_1[ip] == 0 && ix == 1 )
+ {
+ mobility[ip] = relPerm2[0][0][ip] / viscosity[ip];
+ dMob_dP[ip][0] = mobility[ip] * (-dVisc_dP[ip][ix] / viscosity[ip]);
+ dMob_dS[ip][0] = sign[ip] * dPhaseRelPerm2_dPhaseVolFrac[0][0][ip][ip] / viscosity[ip];
+ if constexpr (ENABLE_UPWIND_DEBUG) {
+ if( iter == 0 && ip == 0 )
+ {
+ std::cout << "[UPWIND_DEBUG] Branch: k_up_1[ip]==0 && ix==1" << std::endl;
+ std::cout << "[UPWIND_DEBUG] dMob_dS[ip][0]=" << dMob_dS[ip][0] << ", ix=" << ix << std::endl;
+ }
+ }
+ }
+ else if( k_up_1[ip] == 1 && ix == 1 )
+ {
+ mobility[ip] = faceRelPerm2[0][0][ip] / viscosity[ip];
+ dMob_dP[ip][1] = mobility[ip] * (-dVisc_dP[ip][ix] / viscosity[ip]);
+ dMob_dS[ip][1] = sign[ip] * dfacePhaseRelPerm2_dPhaseVolFrac[0][0][ip][ip] / viscosity[ip];
+ if constexpr (ENABLE_UPWIND_DEBUG) {
+ if( iter == 0 && ip == 0 )
+ {
+ std::cout << "[UPWIND_DEBUG] Branch: k_up_1[ip]==1 && ix==1" << std::endl;
+ std::cout << "[UPWIND_DEBUG] dMob_dS[ip][1]=" << dMob_dS[ip][1] << ", ix=" << ix << std::endl;
+ }
+ }
+ }
+ else
+ {
+ mobility[ip] = relPerm1[0][0][ip] / viscosity[ip];
+ dMob_dP[ip][ix] = mobility[ip] * (-dVisc_dP[ip][ix] / viscosity[ip]);
+ dMob_dS[ip][ix] = sign[ip] * dPhaseRelPerm1_dPhaseVolFrac[0][0][ip][ip] / viscosity[ip];
+ if constexpr (ENABLE_UPWIND_DEBUG) {
+ if( iter == 0 && ip == 0 )
+ {
+ std::cout << "[UPWIND_DEBUG] Branch: else (default)" << std::endl;
+ std::cout << "[UPWIND_DEBUG] dMob_dS[ip][ix]=" << dMob_dS[ip][ix] << ", ix=" << ix << std::endl;
+ }
+ }
+ }
+ real64 constexpr eps = 0.0;
+ total_mobility += mobility[ip] + eps;
+ } // loop over phases
+
+ constexpr bool ENABLE_MOBILITY_DEBUG = false;
+ if constexpr (ENABLE_MOBILITY_DEBUG) {
+ if( iter == 0 && ix == 0 )
+ {
+ std::cout << "[MOBILITY_DEBUG] ix=" << ix << ", S1_face=" << facePhaseVolFrac1[0][0]
+ << ", S2_face=" << facePhaseVolFrac2[0][0] << std::endl;
+ std::cout << "[MOBILITY_DEBUG] mobility[0]=" << mobility[0] << ", mobility[1]=" << mobility[1]
+ << ", total_mobility=" << total_mobility << std::endl;
+ std::cout << "[MOBILITY_DEBUG] dMob_dS[0][0]=" << dMob_dS[0][0] << ", dMob_dS[0][1]=" << dMob_dS[0][1] << std::endl;
+ std::cout << "[MOBILITY_DEBUG] dMob_dS[1][0]=" << dMob_dS[1][0] << ", dMob_dS[1][1]=" << dMob_dS[1][1] << std::endl;
+ if( ix == 0 )
+ {
+ std::cout << "[MOBILITY_DEBUG] faceRelPerm1[0][0][0]=" << faceRelPerm1[0][0][0]
+ << ", faceRelPerm1[0][0][1]=" << faceRelPerm1[0][0][1] << std::endl;
+ std::cout << "[MOBILITY_DEBUG] dfacePhaseRelPerm1_dPhaseVolFrac[0][0][0][0]="
+ << dfacePhaseRelPerm1_dPhaseVolFrac[0][0][0][0]
+ << ", dfacePhaseRelPerm1_dPhaseVolFrac[0][0][1][1]="
+ << dfacePhaseRelPerm1_dPhaseVolFrac[0][0][1][1] << std::endl;
+ }
+ }
+ }
+
+ /// Three Forces Flux Contribution: 1- Viscous 2- Gravitational 3- Capillary
+ constexpr int sign[2] = {1, -1};
+ // real64 constexpr eps = 0.0;
+
+ // loop over phases
+ for( integer ip = 0; ip < 2; ++ip )
+ {
+ // 1- Viscous: pressure gradient depends on all points in the stencil
+ viscous[ip][ix] = mobility[ip] / total_mobility * uT;
+ halfFluxVal[ip][ix] = viscous[ip][ix];
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ real64 dV_dP = sign[ip] * (dMob_dP[0][ke] * mobility[1] - dMob_dP[1][ke] * mobility[0]) / (total_mobility * total_mobility) * uT;
+ real64 dV_dS = sign[ip] * (dMob_dS[0][ke] * mobility[1] - dMob_dS[1][ke] * mobility[0]) / (total_mobility * total_mobility) * uT;
+ real64 dV_du = mobility[ip] / total_mobility;
+
+ if( ix == 0 )
+ {
+ dV1_dS[ip][ke] = dV_dS;
+ dhalfFlux1_dP[ip][ke] = dV_dP;
+ dhalfFlux1_dS[ip][ke] = dV1_dS[ip][ke];
+ dhalfFlux_duT[ip][ix] = dV_du;
+ dV1_dpc[ip][ke] = dV1_dS[ip][ke] * dfacePhaseVolFrac_dCapPres1[0][0][0][0];
+ // GEOS_UNUSED_VAR( dV1_dpc[ip][ke] );
+ GEOS_UNUSED_VAR( dhalfFlux_duT[ip][ix] );
+
+ constexpr bool ENABLE_DV_DEBUG = false;
+ if constexpr (ENABLE_DV_DEBUG) {
+ if( iter == 0 && ip == 0 && ke == 0 )
+ {
+ std::cout << "[DV_DEBUG] ix=" << ix << ", ip=" << ip << ", ke=" << ke
+ << ", dV_dS=" << dV_dS << ", dV1_dS[ip][ke]=" << dV1_dS[ip][ke] << std::endl;
+ std::cout << "[DV_DEBUG] dMob_dS[0][ke]=" << dMob_dS[0][ke] << ", dMob_dS[1][ke]=" << dMob_dS[1][ke] << std::endl;
+ std::cout << "[DV_DEBUG] mobility[0]=" << mobility[0] << ", mobility[1]=" << mobility[1] << std::endl;
+ std::cout << "[DV_DEBUG] uT=" << uT << ", total_mobility=" << total_mobility << std::endl;
+ }
+ }
+ }
+ else
+ {
+ dV2_dS[ip][ke] = dV_dS;
+ dhalfFlux2_dP[ip][ke] = dV_dP;
+ dhalfFlux2_dS[ip][ke] = dV2_dS[ip][ke];
+ dhalfFlux_duT[ip][ix]= dV_du;
+ dV2_dpc[ip][ke] = dV2_dS[ip][ke] * dfacePhaseVolFrac_dCapPres2[0][0][0][0];
+ // GEOS_UNUSED_VAR( dV2_dpc[ip][ke] );
+ GEOS_UNUSED_VAR( dhalfFlux_duT[ip][ix] );
+ }
+ }
+
+ // 2- Gravitational: gravitational head depends only on the two cells connected (same as mean density)
+ bouyancy[ip][ix] = -1.0 * sign[ix] * sign[ip] * mobility[0] * mobility[1] / total_mobility * gravityCof[0] * (density[0] - density[1]);
+ halfFluxVal[ip][ix] += bouyancy[ip][ix];
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ real64 dG_dP = sign[ix] * sign[ip] * (dMob_dP[0][ke] * mobility[1] * mobility[1] + dMob_dP[1][ke] * mobility[0] * mobility[0]) / (total_mobility * total_mobility) * gravityCof[0] *
+ (density[0] - density[1]) +
+ sign[ix] * (mobility[0] * mobility[1]) / total_mobility * (dDens_dP[0][ix] - dDens_dP[1][ix]);
+
+ real64 dG_dS = sign[ix] * sign[ip] * (dMob_dS[0][ke] * mobility[1] * mobility[1] + dMob_dS[1][ke] * mobility[0] * mobility[0]) / (total_mobility * total_mobility) *
+ gravityCof[0] * (density[0] - density[1]);
+
+ if( ix == 0 )
+ {
+ dG1_dS[ip][ke] = dG_dS;
+ dhalfFlux1_dP[ip][ke] -= dG_dP;
+ dhalfFlux1_dS[ip][ke] -= dG1_dS[ip][ke];
+ dG1_dpc[ip][ke] = dG1_dS[ip][ke] * dfacePhaseVolFrac_dCapPres1[0][0][0][0];
+ // GEOS_UNUSED_VAR( dG1_dpc[ip][ke] );
+ }
+ else
+ {
+ dG2_dS[ip][ke] = dG_dS;
+ dhalfFlux2_dP[ip][ke] -= dG_dP;
+ dhalfFlux2_dS[ip][ke] -= dG2_dS[ip][ke];
+ dG2_dpc[ip][ke] = dG2_dS[ip][ke] * dfacePhaseVolFrac_dCapPres2[0][0][0][0];
+ // GEOS_UNUSED_VAR( dG2_dpc[ip][ke] );
+ }
+ }
+
+ // 3- Capillary: capillary pressure contribution
+ capillarity[ip][ix] = -1.0 * sign[ix] * sign[ip] * mobility[0] * mobility[1] / total_mobility * (capGrad[1] -capGrad[0]);
+ halfFluxVal[ip][ix] += capillarity[ip][ix];
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ real64 dC_dP = sign[ix] * sign[ip] * (dMob_dP[0][ke] * mobility[1] * mobility[1] + dMob_dP[1][ke] * mobility[0] * mobility[0]) / (total_mobility * total_mobility) *
+ (capGrad[1] -capGrad[0]) +
+ sign[ix] * sign[ip] * mobility[0] * mobility[1] / total_mobility * (dCapGrad_dP[1][ke] - dCapGrad_dP[0][ke]);
+
+ real64 dC_dS_term1 = sign[ix] * sign[ip] * (dMob_dS[0][ke] * mobility[1] * mobility[1] + dMob_dS[1][ke] * mobility[0] * mobility[0]) / (total_mobility * total_mobility) *
+ (capGrad[1] -capGrad[0]);
+
+ real64 dC_dS_term2 = sign[ix] * sign[ip] * (mobility[0] * mobility[1]) / total_mobility;
+
+ real64 dC_dS_term3 = (dCapGrad_dS[1][ke] - dCapGrad_dS[0][ke]);
+
+ if( ix == 0 )
+ {
+ dC1_dS[ip][ke] = dC_dS_term1 + dC_dS_term2 * dC_dS_term3;
+ dhalfFlux1_dP[ip][ke] -= dC_dP;
+ dhalfFlux1_dS[ip][ke] -= dC1_dS[ip][ke];
+ if( std::fabs( facePhaseVolFrac1[0][0] - 1.0 ) > 1e-8 )
+ {
+ dC1_dpc[ip][ke] = dC1_dS[ip][ke] * dfacePhaseVolFrac_dCapPres1[0][0][0][0];
+ }
+ else
+ {
+ dC1_dpc[ip][ke] = dC_dS_term1 * dfacePhaseVolFrac_dCapPres1[0][0][0][0];
+ }
+
+ // GEOS_UNUSED_VAR( dC1_dpc[ip][ke] );
+ }
+ else
+ {
+ dC2_dS[ip][ke] = dC_dS_term1 + dC_dS_term2 * dC_dS_term3;
+ dhalfFlux2_dP[ip][ke] -= dC_dP;
+ dhalfFlux2_dS[ip][ke] -= dC2_dS[ip][ke];
+ if( std::fabs( facePhaseVolFrac2[0][0] - 1.0 ) > 1e-8 )
+ {
+ dC2_dpc[ip][ke] = dC2_dS[ip][ke] * dfacePhaseVolFrac_dCapPres2[0][0][0][0];
+ }
+ else
+ {
+ dC2_dpc[ip][ke] = dC_dS_term1 * dfacePhaseVolFrac_dCapPres2[0][0][0][0];
+ }
+ // GEOS_UNUSED_VAR( dC2_dpc[ip][ke] );
+ }
+
+ }
+
+
+ if( halfFluxVal[ip][0] > 0.0 )
+ {
+ k_up_0_check[ip] = true;
+ }
+ if( halfFluxVal[ip][1] > 0.0 )
+ {
+ k_up_1_check[ip] = true;
+ }
+
+ } // loop over phases
+
+ } // loop over half fluxes
+
+ check = true;
+
+ bool flip0[2] = {0, 0};
+ bool flip0_k_up[2] = {0, 0};
+ bool flip1[2] = {0, 0};
+ bool flip1_k_up[2] = {0, 0};
+ // loop over phases
+ for( integer ip = 0; ip < 2; ++ip )
+ {
+ bool k_up_0_b = !static_cast< bool >(k_up_0[ip]);
+ bool k_up_1_b = static_cast< bool >(k_up_1[ip]);
+ flip0_k_up[ip] = k_up_0_b;
+ flip1_k_up[ip] = k_up_1_b;
+
+ if( std::fabs( uT ) < 1e-20 )
+ {
+
+ if((std::fabs( halfFluxVal[ip][0] ) < 1e-20) && (std::fabs( halfFluxVal[ip][1] ) < 1e-20))
+ {
+ k_up_0_check[ip] = !k_up_0_b;
+ k_up_1_check[ip] = !k_up_1_b;
+ }
+ else
+ {
+ k_up_0_check[ip] = k_up_0_b;
+ k_up_1_check[ip] = k_up_1_b;
+ }
+
+ if( k_up_0_check[ip] != k_up_0_b )
+ {
+ flip0[ip] = 1;
+ check = false;
+ }
+
+ if( k_up_1_check[ip] != k_up_1_b )
+ {
+ flip1[ip] = 1;
+ check = false;
+ }
+
+ }
+ else
+ {
+ if( std::fabs( halfFluxVal[ip][0] ) < 1e-20 )
+ {
+ k_up_0_check[ip] = k_up_0_b;
+ }
+
+ if( std::fabs( halfFluxVal[ip][1] ) < 1e-20 )
+ {
+ k_up_1_check[ip] = k_up_1_b;
+ }
+
+ if( k_up_0_check[ip] != k_up_0_b )
+ {
+ k_up_0[ip] = static_cast< localIndex >(k_up_0_b);
+ check = false;
+ }
+
+ if( k_up_1_check[ip] != k_up_1_b )
+ {
+ k_up_1[ip] = static_cast< localIndex >(!k_up_1_b);
+ check = false;
+ }
+ }
+
+ }
+
+ if( flip0[0] || flip0[1] )
+ {
+ k_up_0[0] = static_cast< localIndex >(flip0_k_up[0]);
+ k_up_0[1] = static_cast< localIndex >(flip0_k_up[1]);
+ }
+
+ if( flip1[0] || flip1[1] )
+ {
+ k_up_1[0] = static_cast< localIndex >(!flip1_k_up[0]);
+ k_up_1[1] = static_cast< localIndex >(!flip1_k_up[1]);
+ }
+
+ } // while check for BJ PPU
+
+ real64 constexpr eps2 = 1e-12;
+ // real64 constexpr eps2 = 0.0;
+ // newton update
+ dhalfFlux_dpc[0][0] = dhalfFlux1_dS[0][1]*dfacePhaseVolFrac_dCapPres1[0][0][0][0];
+ real64 dhalfFlux_dpc00 = dV1_dpc[0][1] - dG1_dpc[0][1] - dC1_dpc[0][1];
+ dhalfFlux_dpc[0][1] = dhalfFlux2_dS[0][1]*dfacePhaseVolFrac_dCapPres2[0][0][0][0];
+ real64 dhalfFlux_dpc01 = dV2_dpc[0][1] - dG2_dpc[0][1] - dC2_dpc[0][1];
+
+ dhalfFlux_dpc[1][0] = dhalfFlux1_dS[1][1]*dfacePhaseVolFrac_dCapPres1[0][0][0][0];
+ real64 dhalfFlux_dpc10 = dV1_dpc[1][1] - dG1_dpc[1][1] - dC1_dpc[1][1];
+ dhalfFlux_dpc[1][1] = dhalfFlux2_dS[1][1]*dfacePhaseVolFrac_dCapPres2[0][0][0][0];
+ real64 dhalfFlux_dpc11 = dV2_dpc[1][1] - dG2_dpc[1][1] - dC2_dpc[1][1];
+
+ dhalfFlux_dpc[0][0] = dhalfFlux_dpc00;
+ dhalfFlux_dpc[0][1] = dhalfFlux_dpc01;
+ dhalfFlux_dpc[1][0] = dhalfFlux_dpc10;
+ dhalfFlux_dpc[1][1] = dhalfFlux_dpc11;
+
+
+
+ real64 const denom = dhalfFlux_dpc[0][0] - dhalfFlux_dpc[0][1];
+ real64 const denomAbs = LvArray::math::abs( denom );
+ local_jacobian = (denomAbs < eps2) ? (denom >= 0.0 ? eps2 : -eps2) : denom;
+ local_residual = halfFluxVal[0][0] - halfFluxVal[0][1];
+
+
+
+ last_local_residual = local_residual;
+ last_local_jacobian = local_jacobian;
+ last_facePhaseVolFrac1_0 = facePhaseVolFrac1[0][0];
+ last_facePhaseVolFrac2_0 = facePhaseVolFrac2[0][0];
+ last_faceCapPres1 = faceCapPres1[0][0][0];
+ last_faceCapPres2 = faceCapPres2[0][0][0];
+ last_iter = iter;
+
+ constexpr bool ENABLE_NEWTON_ITER_DEBUG = false;
+ if constexpr (ENABLE_NEWTON_ITER_DEBUG) {
+ if( iter < 10 || iter % 10 == 0 || iter >= max_iter - 3 )
+ {
+ std::cout << " [NI] it=" << iter
+ << " Pc=" << Pc_int
+ << " S1=" << facePhaseVolFrac1[0][0]
+ << " S2=" << facePhaseVolFrac2[0][0]
+ << " Pc1f=" << faceCapPres1[0][0][0]
+ << " Pc2f=" << faceCapPres2[0][0][0]
+ << " dSdPc1=" << dfacePhaseVolFrac_dCapPres1[0][0][0][0]
+ << " dSdPc2=" << dfacePhaseVolFrac_dCapPres2[0][0][0][0]
+ << " res=" << local_residual
+ << " jac=" << local_jacobian
+ << " dPc=" << (std::abs( local_jacobian ) > 1e-30 ? local_residual/local_jacobian : 0.0)
+ << std::endl;
+ }
+ }
+
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ if( false )
+ {
+ std::cout << "[LOCAL_SOLVER_DEBUG_ITER] iter=" << iter << ", Pc_int=" << Pc_int
+ << ", Pc1_face=" << faceCapPres1[0][0][0] << ", Pc2_face=" << faceCapPres2[0][0][0] << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG_ITER] S1_face=" << facePhaseVolFrac1[0][0]
+ << ", S2_face=" << facePhaseVolFrac2[0][0] << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG_ITER] halfFluxVal[0][0]=" << halfFluxVal[0][0]
+ << ", halfFluxVal[0][1]=" << halfFluxVal[0][1] << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG_ITER] dhalfFlux_dpc[0][0]=" << dhalfFlux_dpc[0][0]
+ << ", dhalfFlux_dpc[0][1]=" << dhalfFlux_dpc[0][1] << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG_ITER] local_residual=" << local_residual
+ << ", local_jacobian=" << local_jacobian << std::endl;
+ }
+ }
+
+ {
+ real64 absRes = std::fabs( local_residual );
+ if( absRes < best_absRes )
+ {
+ best_absRes = absRes;
+ best_Pc = Pc_int;
+ }
+ }
+
+ bool bracketEstablished = bracket_lo_set && bracket_hi_set;
+ if( !bracketEstablished )
+ {
+ if( !bracket_lo_set && !bracket_hi_set )
+ {
+ Pc_bracket_lo = Pc_int;
+ res_bracket_lo = local_residual;
+ bracket_lo_set = true;
+ }
+ else
+ {
+ if( res_bracket_lo * local_residual < 0.0 )
+ {
+ Pc_bracket_hi = Pc_int;
+ res_bracket_hi = local_residual;
+ bracket_hi_set = true;
+ if( Pc_bracket_lo > Pc_bracket_hi )
+ {
+ real64 tmpPc = Pc_bracket_lo;
+ real64 tmpRes = res_bracket_lo;
+ Pc_bracket_lo = Pc_bracket_hi;
+ res_bracket_lo = res_bracket_hi;
+ Pc_bracket_hi = tmpPc;
+ res_bracket_hi = tmpRes;
+ }
+ }
+ else
+ {
+ Pc_bracket_lo = Pc_int;
+ res_bracket_lo = local_residual;
+ }
+ }
+ }
+ else
+ {
+ if( local_residual * res_bracket_lo <= 0.0 )
+ {
+ Pc_bracket_hi = Pc_int;
+ res_bracket_hi = local_residual;
+ }
+ else
+ {
+ Pc_bracket_lo = Pc_int;
+ res_bracket_lo = local_residual;
+ }
+ }
+ bracketEstablished = bracket_lo_set && bracket_hi_set;
+
+ constexpr bool ENABLE_BRACKET_DEBUG = false;
+ if constexpr (ENABLE_BRACKET_DEBUG) {
+ if( iter < 5 || iter % 10 == 0 )
+ {
+ std::cout << " [BRACKET] iter=" << iter
+ << " established=" << bracketEstablished
+ << " lo=" << Pc_bracket_lo << " (res=" << res_bracket_lo << ")"
+ << " hi=" << Pc_bracket_hi << " (res=" << res_bracket_hi << ")"
+ << " width=" << (Pc_bracket_hi - Pc_bracket_lo) << std::endl;
+ }
+ }
+
+ real64 const convergeTol = ( ENABLE_BEST_SOLUTION_FALLBACK && fallback_used ) ? ( FALLBACK_TOL_FACTOR * tol ) : tol;
+ bool const eitherClamped = faceCapPres1_clamped || faceCapPres2_clamped;
+ bool const rejectClampedConvergence = eitherClamped && !bracketEstablished && iter < max_iter - 5;
+ if( std::fabs( local_residual ) < convergeTol && !rejectClampedConvergence )
+ {
+ converged = 1;
+ // outFile << GEOS_FMT( "{:10.10e}", local_jacobian );
+ // outFile << GEOS_FMT( ",{:10.10e}", local_residual );
+ // outFile << GEOS_FMT( ",{:10.10e}", halfFluxVal[0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", halfFluxVal[0][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", Pc_int_iterate );
+ // outFile << GEOS_FMT( ",{:10.10e}", faceCapPres1[0][0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", faceCapPres2[0][0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", halfFluxVal[1][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", halfFluxVal[1][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", viscous[0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", viscous[1][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", viscous[0][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", viscous[1][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", bouyancy[0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", bouyancy[1][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", bouyancy[0][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", bouyancy[1][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", capillarity[0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", capillarity[1][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", capillarity[0][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", capillarity[1][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", transHat[0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", transHat[1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", gravCoefHat[0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", gravCoef[0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", gravCoef[1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", uT );
+ // outFile << GEOS_FMT( ",{:10.10e}", duT_dP[0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", duT_dS[0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", duT_dP[1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", duT_dS[1] );
+ // outFile << std::endl;
+ break; // Converged
+ }
+
+ {
+ bool atLoBound = (std::fabs( Pc_int - Pc_union_min ) < 1e-10 * (std::fabs( Pc_union_min ) + 1.0));
+ bool atHiBound = (std::fabs( Pc_int - Pc_union_max ) < 1e-10 * (std::fabs( Pc_union_max ) + 1.0));
+ if( (atLoBound || atHiBound) && std::fabs( local_residual ) < 10.0 * tol && !rejectClampedConvergence )
+ {
+ converged = 1;
+ break;
+ }
+ }
+
+ if( iter >= max_iter - 1 )
+ {
+ if constexpr ( ENABLE_SWEEP_FALLBACK )
+ {
+ if( !sweep_active )
+ {
+ sweep_active = true;
+ sweep_newton_iter_end = iter;
+ sweep_best_Pc = best_Pc;
+ sweep_best_absRes = best_absRes;
+ bracket_lo_set = false;
+ bracket_hi_set = false;
+ Pc_int = Pc_union_min;
+ max_iter += 500;
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ std::cout << "[SWEEP] Activated at iter=" << iter
+ << ", sweeping [" << Pc_union_min << ", " << Pc_union_max << "]"
+ << ", dS=" << SWEEP_DS << std::endl;
+ }
+ iter++;
+ continue; // re-enter loop to evaluate at Pc_union_min
+ }
+ else
+ {
+ real64 const sweepAcceptTol = SWEEP_ACCEPT_TOL_FACTOR * tol;
+ if( sweep_best_absRes < sweepAcceptTol )
+ {
+ Pc_int = sweep_best_Pc;
+ converged = 1;
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ std::cout << "[SWEEP] Accepted best: Pc=" << sweep_best_Pc
+ << ", |res|=" << sweep_best_absRes
+ << " < sweepTol=" << sweepAcceptTol << std::endl;
+ }
+ break;
+ }
+ else
+ {
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ std::cout << "[SWEEP] DIVERGED: sweep_best_Pc=" << sweep_best_Pc
+ << ", sweep_best_absRes=" << sweep_best_absRes
+ << ", sweepAcceptTol=" << sweepAcceptTol << std::endl;
+ }
+ div = 1;
+ local_jacobian = 0.0;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ std::cout << "[LOCAL_SOLVER_DEBUG] DIVERGED: best_Pc=" << best_Pc
+ << ", best_absRes=" << best_absRes
+ << ", fallbackTol=" << FALLBACK_TOL_FACTOR * tol << std::endl;
+ }
+ div = 1;
+ local_jacobian = 0.0;
+ break;
+ }
+ }
+
+ if( sweep_active && !bracketEstablished )
+ {
+ real64 const absRes_sweep = std::fabs( local_residual );
+ if( absRes_sweep < sweep_best_absRes )
+ {
+ sweep_best_absRes = absRes_sweep;
+ sweep_best_Pc = Pc_int;
+ }
+
+ real64 const absDSdPc1 = std::fabs( dfacePhaseVolFrac_dCapPres1[0][0][0][0] );
+ real64 const absDSdPc2 = std::fabs( dfacePhaseVolFrac_dCapPres2[0][0][0][0] );
+ real64 const max_absDSdPc = fmax( absDSdPc1, absDSdPc2 );
+ real64 const dPc_max_cap = ( Pc_union_max - Pc_union_min ) / static_cast< real64 >( SWEEP_MIN_POINTS );
+ real64 dPc_step;
+ if( max_absDSdPc > 1e-20 )
+ {
+ dPc_step = SWEEP_DS / max_absDSdPc;
+ }
+ else
+ {
+ dPc_step = dPc_max_cap;
+ }
+ dPc_step = fmin( dPc_step, dPc_max_cap );
+
+ real64 const Pc_next = Pc_int + dPc_step;
+
+ if( Pc_next >= Pc_union_max )
+ {
+ Pc_int = sweep_best_Pc;
+ max_iter = iter + 2;
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ std::cout << "[SWEEP] Completed full sweep, no sign change found."
+ << " sweep_best_Pc=" << sweep_best_Pc
+ << ", sweep_best_absRes=" << sweep_best_absRes << std::endl;
+ }
+ }
+ else
+ {
+ Pc_int = Pc_next;
+ }
+
+ if constexpr (ENABLE_BRACKET_DEBUG) {
+ if( (iter - sweep_newton_iter_end) % 20 == 0 || Pc_next >= Pc_union_max )
+ {
+ std::cout << " [SWEEP] Pc=" << Pc_int
+ << ", dPc_step=" << dPc_step
+ << ", best_Pc=" << sweep_best_Pc
+ << ", best_absRes=" << sweep_best_absRes << std::endl;
+ }
+ }
+ }
+ else if( sweep_active && bracketEstablished )
+ {
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ std::cout << "[SWEEP] Bracket found! Switching to bisection."
+ << " bracket=[" << Pc_bracket_lo << ", " << Pc_bracket_hi << "]" << std::endl;
+ }
+ Pc_int = ( Pc_bracket_lo + Pc_bracket_hi ) / 2.0;
+ }
+ else
+ {
+ real64 deltaPc = local_residual / local_jacobian;
+
+ if( damping )
+ {
+ real64 max_dpc = fmax( fabs( dCapPres1_dfacePhaseVolFrac[0][0][0][0] ), fabs( dCapPres2_dfacePhaseVolFrac[0][0][0][0] ));
+ real64 sign = std::copysign( 1.0, deltaPc );
+ deltaPc = fmin( fabs( deltaPc ), max_dpc * 0.1 );
+ deltaPc *= sign;
+ }
+
+ real64 Pc_newton = Pc_int - deltaPc;
+
+ bool useBisection = false;
+ if( bracketEstablished )
+ {
+ real64 brak_width = Pc_bracket_hi - Pc_bracket_lo;
+ if( Pc_newton <= Pc_bracket_lo || Pc_newton >= Pc_bracket_hi ||
+ std::fabs( deltaPc ) > 0.75 * brak_width )
+ {
+ useBisection = true;
+ }
+ }
+
+ if( useBisection )
+ {
+ Pc_int = ( Pc_bracket_lo + Pc_bracket_hi ) / 2.0;
+ }
+ else
+ {
+ Pc_int = fmin( Pc_union_max, fmax( Pc_newton, Pc_union_min ) );
+ }
+
+ if( std::fabs( Pc_int - prev_Pc_evaluated ) < 1e-10 * std::fabs( Pc_int ) + 1e-30 )
+ {
+ n_same_pc++;
+ }
+ else
+ {
+ n_same_pc = 0;
+ }
+ prev_Pc_evaluated = Pc_int_iterate;
+
+ if( n_same_pc >= 3 && !bracketEstablished )
+ {
+ real64 Pc_probe = 0.0;
+ real64 const Pc_inner_max = fmin( Pc1_max, Pc2_max );
+ if( stuck_probe_level == 0 )
+ {
+ Pc_probe = ( Pc1 + Pc2 ) / 2.0;
+ }
+ else if( stuck_probe_level == 1 )
+ {
+ Pc_probe = Pc_inner_max - 1.0;
+ }
+ else if( stuck_probe_level == 2 )
+ {
+ Pc_probe = Pc_inner_max;
+ }
+ else
+ {
+ if( std::fabs( Pc_int - Pc_union_min ) < std::fabs( Pc_int - Pc_union_max ) )
+ Pc_probe = Pc_union_max;
+ else
+ Pc_probe = Pc_union_min;
+ }
+
+ if( std::fabs( Pc_probe - Pc_int ) > 1e-10 * ( std::fabs( Pc_int ) + 1.0 ) )
+ {
+ Pc_int = Pc_probe;
+ }
+ else
+ {
+ stuck_probe_level++;
+ continue;
+ }
+ stuck_probe_level++;
+ n_same_pc = 0;
+
+ if constexpr (ENABLE_BRACKET_DEBUG) {
+ std::cout << " [STUCK] Forced probe (level " << (stuck_probe_level - 1)
+ << ") to Pc_int=" << Pc_int << std::endl;
+ }
+ }
+
+ if constexpr (ENABLE_BRACKET_DEBUG) {
+ if( iter < 5 || iter % 10 == 0 )
+ {
+ char const * stepName = useBisection ? "BISECTION" : "NEWTON";
+ std::cout << " [STEP] " << stepName
+ << " -> Pc_int=" << Pc_int << std::endl;
+ }
+ }
+ } // end step selection
+
+ // truncate the updated capillary pressure (extended capillary pressure condition) for reporting/plotting:
+
+ real64 faceCapPres1_plot = fmin( Pc1_max, fmax( Pc_int, Pc1_min ));
+ real64 faceCapPres2_plot = fmin( Pc2_max, fmax( Pc_int, Pc2_min ));
+ faceCapPres1_plot = fmin( Pc2_max, fmax( faceCapPres1_plot, Pc2_min ));
+ faceCapPres2_plot = fmin( Pc1_max, fmax( faceCapPres2_plot, Pc1_min ));
+
+ // Write data to the file
+ // outFile << GEOS_FMT( "{:10.10e}", local_jacobian );
+ // outFile << GEOS_FMT( ",{:10.10e}", local_residual );
+ // outFile << GEOS_FMT( ",{:10.10e}", halfFluxVal[0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", halfFluxVal[0][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", Pc_int_iterate );
+ // outFile << GEOS_FMT( ",{:10.10e}", faceCapPres1[0][0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", faceCapPres2[0][0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", halfFluxVal[1][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", halfFluxVal[1][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", viscous[0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", viscous[1][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", viscous[0][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", viscous[1][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", bouyancy[0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", bouyancy[1][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", bouyancy[0][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", bouyancy[1][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", capillarity[0][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", capillarity[1][0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", capillarity[0][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", capillarity[1][1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", transHat[0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", transHat[1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", gravCoefHat[0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", gravCoef[0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", gravCoef[1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", uT );
+ // outFile << GEOS_FMT( ",{:10.10e}", duT_dP[0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", duT_dS[0] );
+ // outFile << GEOS_FMT( ",{:10.10e}", duT_dP[1] );
+ // outFile << GEOS_FMT( ",{:10.10e}", duT_dS[1] );
+ // outFile << std::endl;
+
+ iter++;
+
+ } // while loop
+
+ if( converged )
+ {
+ warmStartPc = Pc_int;
+ }
+
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ const char * modeNames[] = {
+ "DRAINAGE",
+ "IMBIBITION",
+ "DRAINAGE_TO_IMBIBITION",
+ "IMBIBITION_TO_DRAINAGE",
+ "IMBIBITION_TO_DRAINAGE_FROM_SCANNING"
+ };
+ integer mode0 = static_cast< integer >(modes[0]);
+ integer mode1 = static_cast< integer >(modes[1]);
+ const char * name0 = (mode0 >= 0 && mode0 <= 4) ? modeNames[mode0] : "UNKNOWN";
+ const char * name1 = (mode1 >= 0 && mode1 <= 4) ? modeNames[mode1] : "UNKNOWN";
+
+ std::cout << "[LOCAL_SOLVER_DEBUG] converged=" << converged << ", iter=" << last_iter << ", div=" << div << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG] Modes: cell0=" << name0 << " (" << mode0 << "), cell1=" << name1 << " (" << mode1 << ")" << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG] Capillary Pressures: Pc1=" << Pc1 << ", Pc2=" << Pc2 << ", Pc_int=" << Pc_int << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG] Pc bounds: Pc1_min=" << Pc1_min << ", Pc1_max=" << Pc1_max << ", Pc2_min=" << Pc2_min << ", Pc2_max=" << Pc2_max << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG] Initial saturations: S1=" << saturations[0] << ", S2=" << saturations[1] << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG] Last face saturations: S1_face=" << last_facePhaseVolFrac1_0 << ", S2_face=" << last_facePhaseVolFrac2_0 << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG] Last face capillary pressures: Pc1_face=" << last_faceCapPres1 << ", Pc2_face=" << last_faceCapPres2 << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG] Last residual: local_residual=" << last_local_residual << ", local_jacobian=" << last_local_jacobian << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG] Best solution: best_Pc=" << best_Pc << ", best_absRes=" << best_absRes
+ << ", fallbackTol=" << FALLBACK_TOL_FACTOR * tol << ", fallback_used=" << fallback_used << std::endl;
+ std::cout << "[LOCAL_SOLVER_DEBUG] Warm-start: used=" << usedWarmStart << ", warmStartPc=" << warmStartPc << std::endl;
+ if( sweep_active )
+ {
+ std::cout << "[LOCAL_SOLVER_DEBUG] Sweep: active, sweep_best_Pc=" << sweep_best_Pc
+ << ", sweep_best_absRes=" << sweep_best_absRes
+ << ", sweep_iter=" << (last_iter - sweep_newton_iter_end) << std::endl;
+ }
+ }
+
+ if( converged )
+ {
+
+ real64 constexpr eps3 = 1e-12;
+ real64 const denom_deriv = dhalfFlux_dpc[0][0] - dhalfFlux_dpc[0][1];
+ real64 const denomAbs_deriv = LvArray::math::abs( denom_deriv );
+ real64 const denom_protected = (denomAbs_deriv < eps3) ? (denom_deriv >= 0.0 ? eps3 : -eps3) : denom_deriv;
+
+ real64 const dPc_int_dS1 =(-1.0) * (dhalfFlux1_dS[0][0] + dhalfFlux_duT[0][0] * duT_dS[0] - dhalfFlux_duT[0][1] * duT_dS[0]) / denom_protected;
+ real64 const dPc_int_dS2 =(-1.0) * (dhalfFlux_duT[0][0] * duT_dS[1] - dhalfFlux2_dS[0][0] - dhalfFlux_duT[0][1] * duT_dS[1]) / denom_protected;
+ real64 const dPc_int_du =(-1.0) * (dhalfFlux_duT[0][0] - dhalfFlux_duT[0][1]) / denom_protected;
+
+ dFlux_dP[0][0] = (dhalfFlux_duT[0][0] * duT_dP[0] + dhalfFlux_dpc[0][0] * dPc_int_du * duT_dP[0]) * density2[0] + halfFluxVal[0][0] * dDens_dP2[0][0];
+ dFlux_dS[0][0] = (dhalfFlux1_dS[0][0] + dhalfFlux_duT[0][0] * duT_dS[0] + dhalfFlux_dpc[0][0] * dPc_int_dS1) * density2[0];
+
+ dFlux_dP[0][1] = (dhalfFlux_duT[0][1] * duT_dP[1] + dhalfFlux_dpc[0][1] * dPc_int_du * duT_dP[1]) * density2[0] + halfFluxVal[0][1] * dDens_dP2[0][1];
+ dFlux_dS[0][1] = (dhalfFlux2_dS[0][0] + dhalfFlux_duT[0][1] * duT_dS[1] + dhalfFlux_dpc[0][1] * dPc_int_dS2) * density2[0];
+
+ dFlux_dP[1][0] = (dhalfFlux_duT[1][0] * duT_dP[0] + dhalfFlux_dpc[1][0] * dPc_int_du * duT_dP[0]) * density2[1] + halfFluxVal[1][0] * dDens_dP2[1][0];
+ dFlux_dS[1][0] = (dhalfFlux1_dS[1][0] + dhalfFlux_duT[1][0] * duT_dS[0] + dhalfFlux_dpc[1][0] * dPc_int_dS1) * density2[1];
+
+ dFlux_dP[1][1] = (dhalfFlux_duT[1][1] * duT_dP[1] + dhalfFlux_dpc[1][1] * dPc_int_du * duT_dP[1]) * density2[1] + halfFluxVal[1][1] * dDens_dP2[1][1];
+ dFlux_dS[1][1] = (dhalfFlux2_dS[1][0] + dhalfFlux_duT[1][1] * duT_dS[1] + dhalfFlux_dpc[1][1] * dPc_int_dS2) * density2[1];
+
+ fluxVal[0] = halfFluxVal[0][0] * density2[0];
+ fluxVal[1] = halfFluxVal[1][0] * density2[1];
+
+ // std::cout << "dhalfFlux1_dS[0][0]=" << dhalfFlux1_dS[0][0] << ", duT_dS[0]=" << duT_dS[0] << std::endl;
+ // std::cout << "dhalfFlux_dpc[0][1]=" << dhalfFlux_dpc[0][1] << ", dPc_int_dS1=" << dPc_int_dS1 << std::endl;
+ // std::cout << "dhalfFlux1_dS[1][0]=" << dhalfFlux1_dS[1][0] << ", duT_dS[1]=" << duT_dS[1] << std::endl;
+ // std::cout << "dhalfFlux2_dS[0][0]=" << dhalfFlux2_dS[0][0] << ", dPc_int_dS2=" << dPc_int_dS2 << std::endl;
+
+ constexpr bool ENABLE_GLOBAL_DERIVATIVES_DEBUG = false;
+ if constexpr (ENABLE_GLOBAL_DERIVATIVES_DEBUG) {
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] fluxVal[0]=" << fluxVal[0] << ", fluxVal[1]=" << fluxVal[1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dFlux_dP[0][0]=" << dFlux_dP[0][0] << ", dFlux_dP[0][1]=" << dFlux_dP[0][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dFlux_dP[1][0]=" << dFlux_dP[1][0] << ", dFlux_dP[1][1]=" << dFlux_dP[1][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dFlux_dS[0][0]=" << dFlux_dS[0][0] << ", dFlux_dS[0][1]=" << dFlux_dS[0][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dFlux_dS[1][0]=" << dFlux_dS[1][0] << ", dFlux_dS[1][1]=" << dFlux_dS[1][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] Intermediate values:" << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dPc_int_dS1=" << dPc_int_dS1 << ", dPc_int_dS2=" << dPc_int_dS2 << ", dPc_int_du=" << dPc_int_du << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] halfFluxVal[0][0]=" << halfFluxVal[0][0] << ", halfFluxVal[0][1]=" << halfFluxVal[0][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] halfFluxVal[1][0]=" << halfFluxVal[1][0] << ", halfFluxVal[1][1]=" << halfFluxVal[1][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dhalfFlux_dpc[0][0]=" << dhalfFlux_dpc[0][0] << ", dhalfFlux_dpc[0][1]=" << dhalfFlux_dpc[0][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dhalfFlux_dpc[1][0]=" << dhalfFlux_dpc[1][0] << ", dhalfFlux_dpc[1][1]=" << dhalfFlux_dpc[1][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dhalfFlux1_dS[0][0]=" << dhalfFlux1_dS[0][0] << ", dhalfFlux1_dS[0][1]=" << dhalfFlux1_dS[0][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dhalfFlux1_dS[1][0]=" << dhalfFlux1_dS[1][0] << ", dhalfFlux1_dS[1][1]=" << dhalfFlux1_dS[1][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dhalfFlux2_dS[0][0]=" << dhalfFlux2_dS[0][0] << ", dhalfFlux2_dS[0][1]=" << dhalfFlux2_dS[0][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dhalfFlux2_dS[1][0]=" << dhalfFlux2_dS[1][0] << ", dhalfFlux2_dS[1][1]=" << dhalfFlux2_dS[1][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dhalfFlux_duT[0][0]=" << dhalfFlux_duT[0][0] << ", dhalfFlux_duT[0][1]=" << dhalfFlux_duT[0][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] dhalfFlux_duT[1][0]=" << dhalfFlux_duT[1][0] << ", dhalfFlux_duT[1][1]=" << dhalfFlux_duT[1][1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] duT_dS[0]=" << duT_dS[0] << ", duT_dS[1]=" << duT_dS[1] << std::endl;
+ std::cout << "[GLOBAL_DERIVATIVES_DEBUG] density2[0]=" << density2[0] << ", density2[1]=" << density2[1] << std::endl;
+ }
+
+ }
+ else
+ {
+
+ if constexpr (ENABLE_LOCAL_SOLVER_DEBUG) {
+ std::cout << "**********************Diverged*******************" << std::endl;
+
+ const char * modeNames[] = {
+ "DRAINAGE",
+ "IMBIBITION",
+ "DRAINAGE_TO_IMBIBITION",
+ "IMBIBITION_TO_DRAINAGE",
+ "IMBIBITION_TO_DRAINAGE_FROM_SCANNING"
+ };
+ integer mode0 = static_cast< integer >(modes[0]);
+ integer mode1 = static_cast< integer >(modes[1]);
+ const char * name0 = (mode0 >= 0 && mode0 <= 4) ? modeNames[mode0] : "UNKNOWN";
+ const char * name1 = (mode1 >= 0 && mode1 <= 4) ? modeNames[mode1] : "UNKNOWN";
+ std::cout << " [DEBUG] Modes: cell0=" << name0 << " (" << mode0 << "), cell1=" << name1 << " (" << mode1 << ")" << std::endl;
+ std::cout << " [DEBUG] Capillary Pressures: Pc1=" << Pc1 << ", Pc2=" << Pc2 << ", Pc_int=" << Pc_int << std::endl;
+ std::cout << " [DEBUG] Pc bounds: Pc1_min=" << Pc1_min << ", Pc1_max=" << Pc1_max << ", Pc2_min=" << Pc2_min << ", Pc2_max=" << Pc2_max << std::endl;
+ std::cout << " [DEBUG] Initial saturations: S1=" << saturations[0] << ", S2=" << saturations[1] << std::endl;
+ std::cout << " [DEBUG] Last iteration values: iter=" << last_iter << ", div=" << div << std::endl;
+ std::cout << " [DEBUG] Last face saturations: S1_face=" << last_facePhaseVolFrac1_0 << ", S2_face=" << last_facePhaseVolFrac2_0 << std::endl;
+ std::cout << " [DEBUG] Last face capillary pressures: Pc1_face=" << last_faceCapPres1 << ", Pc2_face=" << last_faceCapPres2 << std::endl;
+ std::cout << " [DEBUG] Last residual: local_residual=" << last_local_residual << ", local_jacobian=" << last_local_jacobian << std::endl;
+ }
+
+ }
+
+ phi[0] = fluxVal[0];
+ phi[1] = fluxVal[1];
+
+ grad_phi_P[0] = dFlux_dP[0][0];
+ grad_phi_P[1] = dFlux_dP[0][1];
+ grad_phi_P[2] = dFlux_dP[1][0];
+ grad_phi_P[3] = dFlux_dP[1][1];
+
+ grad_phi_S[0] = dFlux_dS[0][0];
+ grad_phi_S[1] = dFlux_dS[0][1];
+ grad_phi_S[2] = dFlux_dS[1][0];
+ grad_phi_S[3] = dFlux_dS[1][1];
+
+
+// Close the file after writing
+ // outFile.close();
+
+ } );
+
+ } );
+
+ } );
+
+ } );
+
+
+}
/******************************** FluxComputeKernelBase ********************************/
@@ -78,17 +2293,23 @@ class FluxComputeKernelBase
fields::flow::gravityCoefficient,
fields::immiscibleMultiphaseFlow::phaseVolumeFraction,
fields::immiscibleMultiphaseFlow::phaseMobility,
+ fields::immiscibleMultiphaseFlow::phaseMass_n,
fields::immiscibleMultiphaseFlow::dPhaseMobility >;
using MultiphaseFluidAccessors =
StencilMaterialAccessors< constitutive::TwoPhaseImmiscibleFluid,
fields::twophaseimmisciblefluid::phaseDensity,
- fields::twophaseimmisciblefluid::dPhaseDensity >;
+ fields::twophaseimmisciblefluid::dPhaseDensity,
+ fields::twophaseimmisciblefluid::phaseViscosity,
+ fields::twophaseimmisciblefluid::dPhaseViscosity >;
using CapPressureAccessors =
StencilMaterialAccessors< CapillaryPressureBase,
fields::cappres::phaseCapPressure,
- fields::cappres::dPhaseCapPressure_dPhaseVolFraction >;
+ fields::cappres::dPhaseCapPressure_dPhaseVolFraction
+ >;
+ // ,fields::cappres::jFuncMultiplier >;
+
using PermeabilityAccessors =
StencilMaterialAccessors< PermeabilityBase,
@@ -135,12 +2356,16 @@ class FluxComputeKernelBase
m_gravCoef( multiPhaseFlowAccessors.get( fields::flow::gravityCoefficient {} ) ),
m_pres( multiPhaseFlowAccessors.get( fields::flow::pressure {} ) ),
m_phaseVolFrac( multiPhaseFlowAccessors.get( fields::immiscibleMultiphaseFlow::phaseVolumeFraction {} ) ),
+ m_phaseMass_n( multiPhaseFlowAccessors.get( fields::immiscibleMultiphaseFlow::phaseMass_n {} ) ),
m_mob( multiPhaseFlowAccessors.get( fields::immiscibleMultiphaseFlow::phaseMobility {} ) ),
m_dMob( multiPhaseFlowAccessors.get( fields::immiscibleMultiphaseFlow::dPhaseMobility {} ) ),
m_dens( fluidAccessors.get( fields::twophaseimmisciblefluid::phaseDensity {} ) ),
+ m_visc( fluidAccessors.get( fields::twophaseimmisciblefluid::phaseViscosity {} ) ),
m_dDens_dPres( fluidAccessors.get( fields::twophaseimmisciblefluid::dPhaseDensity {} ) ),
+ m_dVisc_dPres( fluidAccessors.get( fields::twophaseimmisciblefluid::dPhaseViscosity {} ) ),
m_phaseCapPressure( capPressureAccessors.get( fields::cappres::phaseCapPressure {} ) ),
m_dPhaseCapPressure_dPhaseVolFrac( capPressureAccessors.get( fields::cappres::dPhaseCapPressure_dPhaseVolFraction {} ) ),
+ // m_jFuncMultiplier( capPressureAccessors.get( fields::cappres::jFuncMultiplier {} ) ),
m_localMatrix( localMatrix ),
m_localRhs( localRhs ),
m_hasCapPressure ( hasCapPressure ),
@@ -174,21 +2399,26 @@ class FluxComputeKernelBase
/// Views on pressure and phase volume fraction
ElementViewConst< arrayView1d< real64 const > > const m_pres;
ElementViewConst< arrayView2d< real64 const, immiscibleFlow::USD_PHASE > > const m_phaseVolFrac;
+ ElementViewConst< arrayView2d< real64 const, immiscibleFlow::USD_PHASE > > const m_phaseMass_n;
/// Views on fluid mobility
ElementViewConst< arrayView2d< real64 const, immiscibleFlow::USD_PHASE > > const m_mob;
ElementViewConst< arrayView3d< real64 const, immiscibleFlow::USD_PHASE_DS > > const m_dMob;
- /// Views on fluid density
+ /// Views on fluid density and viscosity
ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_dens;
+ ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_visc;
ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dDens_dPres;
+ ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dVisc_dPres;
/// Views on capillary pressure
ElementViewConst< arrayView3d< real64 const, cappres::USD_CAPPRES > > const m_phaseCapPressure;
ElementViewConst< arrayView4d< real64 const, cappres::USD_CAPPRES_DS > > const m_dPhaseCapPressure_dPhaseVolFrac;
+ // ElementViewConst< arrayView2d< real64 const > > const m_jFuncMultiplier;
// Residual and jacobian
+
/// View on the local CRS matrix
CRSMatrixView< real64, globalIndex const > const m_localMatrix;
/// View on the local RHS
@@ -314,6 +2544,11 @@ class FluxComputeKernel : public FluxComputeKernelBase
/// Derivatives of transmissibility with respect to pressure
real64 dTrans_dPres[maxNumConns][2]{};
+ /// Transmissibility
+ real64 transmissibilityHat[maxNumConns][2]{};
+ /// Derivatives of transmissibility with respect to pressure
+ real64 dTransHat_dPres[maxNumConns][2]{};
+
// Local degrees of freedom and local residual/jacobian
/// Indices of the matrix rows/columns corresponding to the dofs in this face
@@ -372,7 +2607,7 @@ class FluxComputeKernel : public FluxComputeKernelBase
* @param[inout] stack the stack variables
* @param[in] NoOpFunc the function used to customize the computation of the flux
*/
- template< typename FUNC = NoOpFunc > // should change to multiphase
+ template< typename FUNC = NoOpFunc > // should change to multiphase
GEOS_HOST_DEVICE
void computeFlux( localIndex const iconn,
StackVariables & stack,
@@ -437,22 +2672,22 @@ class FluxComputeKernel : public FluxComputeKernelBase
continue;
}
- real64 const density = m_dens[seri[ke]][sesri[ke]][sei[ke]][0][ip]; // r = rho1 || rho2
- real64 const dDens_dP = m_dDens_dPres[seri[ke]][sesri[ke]][sei[ke]][0][ip][Deriv::dP]; // dr/dP = dr1/dP1 || dr2/dP
+ real64 const density = m_dens[seri[ke]][sesri[ke]][sei[ke]][0][ip]; // r = rho1 || rho2
+ real64 const dDens_dP = m_dDens_dPres[seri[ke]][sesri[ke]][sei[ke]][0][ip][Deriv::dP]; // dr/dP = dr1/dP1 || dr2/dP
// average density and derivatives
- densMean[ip] += density; // rho = (rho1 + rho2)
- dDensMean_dP[ip][ke] = dDens_dP; // drho/dP = { (dr1/dP1) , (dr2/dP2) }
+ densMean[ip] += density; // rho = (rho1 + rho2)
+ dDensMean_dP[ip][ke] = dDens_dP; // drho/dP = { (dr1/dP1) , (dr2/dP2) }
denom++;
}
if( denom > 1 )
{
- densMean[ip] /= denom; // rho = (rho1 + rho2) / denom
+ densMean[ip] /= denom; // rho = (rho1 + rho2) / denom
for( integer ke = 0; ke < 2; ++ke )
{
- dDensMean_dP[ip][ke] /= denom; // drho/dP = { (dr1/dP1) / denom , (dr2/dP2) / denom }
+ dDensMean_dP[ip][ke] /= denom; // drho/dP = { (dr1/dP1) / denom , (dr2/dP2) / denom }
}
}
@@ -471,106 +2706,114 @@ class FluxComputeKernel : public FluxComputeKernelBase
localIndex const esr = sesri[ke];
localIndex const ei = sei[ke];
- real64 const pressure = m_pres[er][esr][ei]; // P = P1 || P2
- presGrad[ip] += trans[ke] * pressure; // DPv = T (P1 - P2)
- dPresGrad_dTrans += signPotDiff[ke] * pressure; // dDPv/dT = (P1 - P2)
- dPresGrad_dP[ip][ke] = trans[ke]; // dDPv/dP = { T , -T }
+ real64 const pressure = m_pres[er][esr][ei]; // P = P1 || P2
+ presGrad[ip] += trans[ke] * pressure; // DPv = T (P1 - P2)
+ dPresGrad_dTrans += signPotDiff[ke] * pressure; // dDPv/dT = (P1 - P2)
+ dPresGrad_dP[ip][ke] = trans[ke]; // dDPv/dP = { T , -T }
- real64 const gravD = trans[ke] * m_gravCoef[er][esr][ei]; // D = T g z1 || -T g z2
- real64 pot = trans[ke] * pressure - densMean[ip] * gravD; // Phi = T P1 - rho T g z1 || -T P2 + rho T g z2
+ real64 const gravD = trans[ke] * m_gravCoef[er][esr][ei]; // D = T g z1 || -T g z2
+ real64 pot = trans[ke] * pressure - densMean[ip] * gravD; // Phi = T P1 - rho T g z1 || -T P2 + rho T g z2
- gravHead[ip] += densMean[ip] * gravD; // DPg = rho (T g z1 - T g z2) = T rho g (z1 - z2)
- dGravHead_dTrans += signPotDiff[ke] * densMean[ip] * m_gravCoef[er][esr][ei]; // dDPg/dT = rho g z1 - rho g z2 = rho g (z1 - z2)
+ gravHead[ip] += densMean[ip] * gravD; // DPg = rho (T g z1 - T g z2) = T rho g (z1 -
+ // z2)
+ dGravHead_dTrans += signPotDiff[ke] * densMean[ip] * m_gravCoef[er][esr][ei]; // dDPg/dT = rho g z1 - rho g z2 = rho g (z1 -
+ // z2)
for( integer i = 0; i < 2; ++i )
{
- dGravHead_dP[ip][i] += dDensMean_dP[ip][i] * gravD; // dDPg/dP = {drho/dP1 * T g (z1 - z2) , drho/dP2 * T g (z1 - z2)}
+ dGravHead_dP[ip][i] += dDensMean_dP[ip][i] * gravD; // dDPg/dP = {drho/dP1 * T g (z1 - z2) , drho/dP2 * T g (z1 - z2)}
}
- if( m_hasCapPressure ) // check sign convention
+ if( m_hasCapPressure ) // check sign convention
{
- real64 const capPres = m_phaseCapPressure[er][esr][ei][0][ip]; // Pc = Pc1 || Pc2
- dCapGrad_dTrans -= signPotDiff[ke] * capPres; // dDPc/dT = (-Pc1 + Pc2)
- pot -= trans[ke] * capPres; // Phi = T P1 - rho T g z1 - T Pc1 || -T P2 + rho T g z2 + T
- // Pc2
- capGrad[ip] -= trans[ke] * capPres; // DPc = T (-Pc1 + Pc2)
+ real64 const capPres = m_phaseCapPressure[er][esr][ei][0][ip]; // Pc = Pc1 || Pc2
+ dCapGrad_dTrans -= signPotDiff[ke] * capPres; // dDPc/dT = (-Pc1 + Pc2)
+ pot -= trans[ke] * capPres; // Phi = T P1 - rho T g z1 - T Pc1 || -T P2 + rho T g z2 + T
+ // Pc2
+ capGrad[ip] -= trans[ke] * capPres; // DPc = T (-Pc1 + Pc2)
}
- potScale = fmax( potScale, fabs( pot ) ); // maxPhi = Phi1 > Phi2 ? Phi1 : Phi2
+ potScale = fmax( potScale, fabs( pot ) ); // maxPhi = Phi1 > Phi2 ? Phi1 : Phi2
}
for( integer ke = 0; ke < 2; ++ke )
{
- dPresGrad_dP[ip][ke] += dTrans_dP[ke] * dPresGrad_dTrans; // dDPv/dP = { T + dT/dP1 * (P1 - P2) , -T + dT/dP2 * (P1 - P2)}
- dGravHead_dP[ip][ke] += dTrans_dP[ke] * dGravHead_dTrans; // dDPg/dP = { drho/dP1 * T g (z1 - z2) + dT/dP1 * rho g (z1 - z2) ,
- // drho/dP2 * T g (z1 - z2) + dT/dP2 * rho g (z1 - z2) }
+ dPresGrad_dP[ip][ke] += dTrans_dP[ke] * dPresGrad_dTrans; // dDPv/dP = { T + dT/dP1 * (P1 - P2) , -T + dT/dP2 * (P1 - P2)}
+ dGravHead_dP[ip][ke] += dTrans_dP[ke] * dGravHead_dTrans; // dDPg/dP = { drho/dP1 * T g (z1 - z2) + dT/dP1 * rho g (z1 - z2)
+ // ,
+ // drho/dP2 * T g (z1 - z2) + dT/dP2 * rho g (z1 - z2)
+ // }
if( m_hasCapPressure )
{
- real64 const dCapPres_dS = m_dPhaseCapPressure_dPhaseVolFrac[seri[ke]][sesri[ke]][sei[ke]][0][ip][ip]; // dPc/dS = dPc1/dS1 ||
- // dPc2/dS2
- dCapGrad_dP[ip][ke] += dTrans_dP[ke] * dCapGrad_dTrans; // dDPc/dP = { dT/dP1 *
- // (-Pc1 + Pc2) ,
- // dT/dP2 *
- // (-Pc1 + Pc2) }
- dCapGrad_dS[ip][ke] -= trans[ke] * dCapPres_dS; // dDPc/dS = { -T *
- // dPc1/dS1 , T *
- // dPc2/dS2 }
+ real64 const dCapPres_dS = m_dPhaseCapPressure_dPhaseVolFrac[seri[ke]][sesri[ke]][sei[ke]][0][ip][ip]; // dPc/dS = dPc1/dS1
+ // ||
+ // dPc2/dS2
+ dCapGrad_dP[ip][ke] += dTrans_dP[ke] * dCapGrad_dTrans; // dDPc/dP = { dT/dP1
+ // *
+ // (-Pc1 + Pc2) ,
+ // dT/dP2
+ // *
+ // (-Pc1 + Pc2) }
+ dCapGrad_dS[ip][ke] -= trans[ke] * dCapPres_dS; // dDPc/dS = { -T *
+ // dPc1/dS1 , T *
+ // dPc2/dS2 }
}
}
// *** upwinding ***
// compute potential gradient
- real64 potGrad = presGrad[ip] - gravHead[ip]; // DPhi = T (P1 - P2) - T rho g (z1 - z2)
+ real64 potGrad = presGrad[ip] - gravHead[ip]; // DPhi = T (P1 - P2) - T rho g (z1 - z2)
if( m_hasCapPressure )
{
- potGrad += capGrad[ip]; // DPhi = T (P1 - P2) - T rho g (z1 - z2) + T (-Pc1 + Pc2)
+ potGrad += capGrad[ip]; // DPhi = T (P1 - P2) - T rho g (z1 - z2) + T (-Pc1 + Pc2)
}
// compute upwinding tolerance
real64 constexpr upwRelTol = 1e-8;
- real64 const upwAbsTol = fmax( potScale * upwRelTol, LvArray::NumericLimits< real64 >::epsilon ); // abstol = maxPhi * tol > eps ?
- // maxPhi * tol : eps
+ real64 const upwAbsTol = fmax( potScale * upwRelTol, LvArray::NumericLimits< real64 >::epsilon ); // abstol = maxPhi * tol > eps
+ // ?
+ // maxPhi * tol : eps
// decide mobility coefficients - smooth variation in [-upwAbsTol; upwAbsTol]
- real64 const alpha = ( potGrad + upwAbsTol ) / ( 2 * upwAbsTol ); // alpha = (DPhi + abstol) / abstol / 2
+ real64 const alpha = ( potGrad + upwAbsTol ) / ( 2 * upwAbsTol ); // alpha = (DPhi + abstol) / abstol / 2
// choose upstream cell
- if( alpha <= 0.0 || alpha >= 1.0 ) // no smoothing needed
+ if( alpha <= 0.0 || alpha >= 1.0 ) // no smoothing needed
{
- localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); // 1 upwind -> k_up = 0 || 2 upwind -> k_up = 1
+ localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); // 1 upwind -> k_up = 0 || 2 upwind -> k_up = 1
- mobility[ip] = m_mob[seri[k_up]][sesri[k_up]][sei[k_up]][ip]; // M = Mupstream
- dMob_dP[ip][k_up] = m_dMob[seri[k_up]][sesri[k_up]][sei[k_up]][ip][Deriv::dP]; // dM/dP = {dM/dP1 , 0} OR {0 , dM/dP2}
- dMob_dS[ip][k_up] = m_dMob[seri[k_up]][sesri[k_up]][sei[k_up]][ip][Deriv::dS]; // dM/dS = {dM/dS1 , 0} OR {0 , dM/dS2}
+ mobility[ip] = m_mob[seri[k_up]][sesri[k_up]][sei[k_up]][ip]; // M = Mupstream
+ dMob_dP[ip][k_up] = m_dMob[seri[k_up]][sesri[k_up]][sei[k_up]][ip][Deriv::dP]; // dM/dP = {dM/dP1 , 0} OR {0 , dM/dP2}
+ dMob_dS[ip][k_up] = m_dMob[seri[k_up]][sesri[k_up]][sei[k_up]][ip][Deriv::dS]; // dM/dS = {dM/dS1 , 0} OR {0 , dM/dS2}
}
- else // perform smoothing
+ else // perform smoothing
{
real64 const mobWeights[2] = { alpha, 1.0 - alpha };
for( integer ke = 0; ke < 2; ++ke )
{
- mobility[ip] += mobWeights[ke] * m_mob[seri[ke]][sesri[ke]][sei[ke]][ip]; // M = alpha * M1 + (1 - alpha) * M2
- dMob_dP[ip][ke] = mobWeights[ke] * m_dMob[seri[ke]][sesri[ke]][sei[ke]][ip][Deriv::dP]; // dM/dP = {alpha * dM1/dP1 , (1 -
- // alpha) * dM2/dP2}
- dMob_dS[ip][ke] = mobWeights[ke] * m_dMob[seri[ke]][sesri[ke]][sei[ke]][ip][Deriv::dS]; // dM/dP = {alpha * dM1/dS1 , (1 -
- // alpha) * dM2/dS2}
+ mobility[ip] += mobWeights[ke] * m_mob[seri[ke]][sesri[ke]][sei[ke]][ip]; // M = alpha * M1 + (1 - alpha) * M2
+ dMob_dP[ip][ke] = mobWeights[ke] * m_dMob[seri[ke]][sesri[ke]][sei[ke]][ip][Deriv::dP]; // dM/dP = {alpha * dM1/dP1 , (1 -
+ // alpha) * dM2/dP2}
+ dMob_dS[ip][ke] = mobWeights[ke] * m_dMob[seri[ke]][sesri[ke]][sei[ke]][ip][Deriv::dS]; // dM/dP = {alpha * dM1/dS1 , (1 -
+ // alpha) * dM2/dS2}
}
}
// pressure gradient depends on all points in the stencil
for( integer ke = 0; ke < 2; ++ke )
{
- dFlux_dP[ip][ke] += dPresGrad_dP[ip][ke]; // dF/dP = { T + dT/dP1 * (P1 - P2) ,
- // -T + dT/dP2 * (P1 - P2) }
+ dFlux_dP[ip][ke] += dPresGrad_dP[ip][ke]; // dF/dP = { T + dT/dP1 * (P1 - P2) ,
+ // -T + dT/dP2 * (P1 - P2) }
}
// gravitational head depends only on the two cells connected (same as mean density)
for( integer ke = 0; ke < 2; ++ke )
{
- dFlux_dP[ip][ke] -= dGravHead_dP[ip][ke]; // dF/dP = { T + dT/dP1 * (P1 - P2) - drho/dP1 * T g (z1 - z2) - dT/dP1 * rho g (z1 -
- // z2) ,
- // -T + dT/dP2 * (P1 - P2) - drho/dP2 * T g (z1 - z2) - dT/dP2 * rho g (z1 -
- // z2) }
+ dFlux_dP[ip][ke] -= dGravHead_dP[ip][ke]; // dF/dP = { T + dT/dP1 * (P1 - P2) - drho/dP1 * T g (z1 - z2) - dT/dP1 * rho g (z1 -
+ // z2) ,
+ // -T + dT/dP2 * (P1 - P2) - drho/dP2 * T g (z1 - z2) - dT/dP2 * rho g (z1 -
+ // z2) }
}
// capillary pressure contribution
@@ -578,38 +2821,38 @@ class FluxComputeKernel : public FluxComputeKernelBase
{
for( integer ke = 0; ke < 2; ++ke )
{
- dFlux_dP[ip][ke] += dCapGrad_dP[ip][ke]; // dF/dP = { T + dT/dP1 * (P1 - P2) - drho/dP1 * T g (z1 - z2) - dT/dP1 * rho g (z1
- // - z2) + dT/dP1 * (-Pc1 + Pc2) ,
- // -T + dT/dP2 * (P1 - P2) - drho/dP2 * T g (z1 - z2) - dT/dP2 * rho g (z1
- // - z2) + dT/dP2 * (-Pc1 + Pc2) }
+ dFlux_dP[ip][ke] += dCapGrad_dP[ip][ke]; // dF/dP = { T + dT/dP1 * (P1 - P2) - drho/dP1 * T g (z1 - z2) - dT/dP1 * rho g (z1
+ // - z2) + dT/dP1 * (-Pc1 + Pc2) ,
+ // -T + dT/dP2 * (P1 - P2) - drho/dP2 * T g (z1 - z2) - dT/dP2 * rho g (z1
+ // - z2) + dT/dP2 * (-Pc1 + Pc2) }
- dFlux_dS[ip][ke] += dCapGrad_dS[ip][ke]; // dF/dS = { T * -dPc/dS1 , T * dPc/dS2 }
+ dFlux_dS[ip][ke] += dCapGrad_dS[ip][ke]; // dF/dS = { T * -dPc/dS1 , T * dPc/dS2 }
}
}
// compute the flux and derivatives using upstream cell mobility
- fluxVal[ip] = mobility[ip] * potGrad; // F = M * DPhi
+ fluxVal[ip] = mobility[ip] * potGrad; // F = M * DPhi
for( integer ke = 0; ke < 2; ++ke )
{
- dFlux_dP[ip][ke] *= mobility[ip]; // dF/dP = { M [ T + dT/dP1 * (P1 - P2) - drho/dP1 * T g (z1 - z2) - dT/dP1 * rho g (z1 -
- // z2) + dT/dP1 * (-Pc1 + Pc2)] ,
- // M [-T + dT/dP2 * (P1 - P2) - drho/dP2 * T g (z1 - z2) - dT/dP2 * rho g (z1 -
- // z2) + dT/dP2 * (-Pc1 + Pc2)] }
+ dFlux_dP[ip][ke] *= mobility[ip]; // dF/dP = { M [ T + dT/dP1 * (P1 - P2) - drho/dP1 * T g (z1 - z2) - dT/dP1 * rho g (z1 -
+ // z2) + dT/dP1 * (-Pc1 + Pc2)] ,
+ // M [-T + dT/dP2 * (P1 - P2) - drho/dP2 * T g (z1 - z2) - dT/dP2 * rho g (z1 -
+ // z2) + dT/dP2 * (-Pc1 + Pc2)] }
- dFlux_dS[ip][ke] *= mobility[ip]; // dF/dS = { M [T * -dPc/dS1] , M [T * dPc/dS2] }
+ dFlux_dS[ip][ke] *= mobility[ip]; // dF/dS = { M [T * -dPc/dS1] , M [T * dPc/dS2] }
}
// add contribution from upstream cell mobility derivatives
for( integer ke = 0; ke < 2; ++ke )
{
- dFlux_dP[ip][ke] += dMob_dP[ip][ke] * potGrad; // dF/dP = { M [ T + dT/dP1 * (P1 - P2) - drho1/dP * T g (z1 - z2) - dT/dP1 *
- // rho g (z1 - z2) + dT/dP1 * (-Pc1 + Pc2)] + dM/dP1 * DPhi ,
- // M [-T + dT/dP2 * (P1 - P2) - drho2/dP * T g (z1 - z2) - dT/dP2 *
- // rho g (z1 - z2) + dT/dP2 * (-Pc1 + Pc2)] + dM/dP2 * DPhi }
+ dFlux_dP[ip][ke] += dMob_dP[ip][ke] * potGrad; // dF/dP = { M [ T + dT/dP1 * (P1 - P2) - drho1/dP * T g (z1 - z2) - dT/dP1 *
+ // rho g (z1 - z2) + dT/dP1 * (-Pc1 + Pc2)] + dM/dP1 * DPhi ,
+ // M [-T + dT/dP2 * (P1 - P2) - drho2/dP * T g (z1 - z2) - dT/dP2 *
+ // rho g (z1 - z2) + dT/dP2 * (-Pc1 + Pc2)] + dM/dP2 * DPhi }
- dFlux_dS[ip][ke] += dMob_dS[ip][ke] * potGrad; // dF/dS = { M [T * -dPc/dS1] + dM/dS1 * DPhi , M [T * dPc/dS2] + dM/dS2 * DPhi
- // }
+ dFlux_dS[ip][ke] += dMob_dS[ip][ke] * potGrad; // dF/dS = { M [T * -dPc/dS1] + dM/dS1 * DPhi , M [T * dPc/dS2] + dM/dS2 * DPhi
+ // }
}
// populate local flux vector and derivatives
@@ -630,14 +2873,14 @@ class FluxComputeKernel : public FluxComputeKernelBase
}
// Customize the kernel with this lambda
- kernelOp( k, seri, sesri, sei, connectionIndex, alpha, mobility, potGrad, fluxVal, dFlux_dP, dFlux_dS ); // Not sure what this
- // does
+ kernelOp( k, seri, sesri, sei, connectionIndex, alpha, mobility, potGrad, fluxVal, dFlux_dP, dFlux_dS ); // Not sure what this
+ // does
- } // loop over phases
+ } // loop over phases
connectionIndex++;
}
- } // loop over connection elements
+ } // loop over connection elements
}
/**
@@ -645,7 +2888,7 @@ class FluxComputeKernel : public FluxComputeKernelBase
* @param[in] iconn the connection index
* @param[inout] stack the stack variables
*/
- template< typename FUNC = NoOpFunc > // should change to multiphase
+ template< typename FUNC = NoOpFunc > // should change to multiphase
GEOS_HOST_DEVICE
void complete( localIndex const iconn,
StackVariables & stack,
@@ -732,28 +2975,845 @@ class FluxComputeKernel : public FluxComputeKernelBase
};
-/****************************************** */
-
/**
- * @class FluxComputeKernelFactory
+ * @class FaceBasedAssemblyInterfaceConditionKernel
+ * @tparam NUM_DOF number of degrees of freedom
+ * @tparam STENCILWRAPPER the type of the stencil wrapper
+ * @tparam CAPPRESWRAPPER the type of the capillary pressure wrapper
+ * @tparam RELPERMWRAPPER the type of the realtive permeability wrapper
+ * @brief Define the interface for the assembly kernel in charge of flux terms
*/
-class FluxComputeKernelFactory
+// template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER, typename CAPPRESWRAPPER, typename RELPERMWRAPPER >
+template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER >
+class FluxComputeInterfaceConditionKernel : public FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >
{
public:
+ using AbstractBase = FluxComputeKernelBase;
+ using DofNumberAccessor = AbstractBase::DofNumberAccessor;
+ using ImmiscibleMultiphaseFlowAccessors = AbstractBase::ImmiscibleMultiphaseFlowAccessors;
+ using MultiphaseFluidAccessors = AbstractBase::MultiphaseFluidAccessors;
+ using CapPressureAccessors = AbstractBase::CapPressureAccessors;
+ using PermeabilityAccessors = AbstractBase::PermeabilityAccessors;
+
+ using Base = FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >;
+ using Deriv = typename Base::Deriv;
+ using StackVariables = typename Base::StackVariables;
+ using Base::numEqn;
+ using Base::numDof;
+ using Base::m_stencilWrapper;
+ using Base::m_dofNumber;
+ using Base::m_rankOffset;
+ using Base::m_localMatrix;
+ using Base::m_localRhs;
+ using Base::m_numPhases;
+ using Base::m_permeability;
+ using Base::m_dPerm_dPres;
+ using Base::m_phaseVolFrac;
+ using Base::m_phaseMass_n;
+ using Base::m_phaseCapPressure;
+ // using Base::m_jFuncMultiplier;
+ using Base::m_dPhaseCapPressure_dPhaseVolFrac;
+ using Base::m_dens;
+ using Base::m_dDens_dPres;
+ using Base::m_visc;
+ using Base::m_dVisc_dPres;
+ using Base::m_dMob;
+ using Base::m_mob;
+ using Base::m_gravCoef;
+ using Base::m_ghostRank;
+ using Base::m_dt;
+ using Base::m_hasCapPressure;
+ using Base::m_useTotalMassEquation;
+ using Base::m_checkPhasePresenceInGravity;
+ using Base::m_seri;
+ using Base::m_sesri;
+ using Base::m_sei;
+ using Base::m_pres;
+
/**
- * @brief Create a new kernel and launch
- * @tparam POLICY the policy used in the RAJA kernel
- * @tparam STENCILWRAPPER the type of the stencil wrapper
+ * @brief Constructor for the kernel interface
+ * @param[in] numPhases number of fluid phases
* @param[in] rankOffset the offset of my MPI rank
- * @param[in] dofKey string to get the element degrees of freedom numbers
- * @param[in] solverName name of the solver (to name accessors)
- * @param[in] elemManager reference to the element region manager
* @param[in] stencilWrapper reference to the stencil wrapper
+ * @param[in] capPressureWrapper reference to the capillary pressure wrapper
+ * @param[in] dofNumberAccessor
+ * @param[in] multiPhaseFlowAccessors
+ * @param[in] fluidAccessors
+ * @param[in] capPressureAccessors
+ * @param[in] permeabilityAccessors
* @param[in] dt time step size
* @param[inout] localMatrix the local CRS matrix
* @param[inout] localRhs the local right-hand side vector
- */
+ * @param[in] hasCapPressure flags for capillary pressure
+ * @param[in] useTotalMassEquation flags for using total velocity formulation
+ */
+ FluxComputeInterfaceConditionKernel( integer const numPhases,
+ globalIndex const rankOffset,
+ STENCILWRAPPER const & stencilWrapper,
+ // CAPPRESWRAPPER const & capPressureWrapper,
+ // RELPERMWRAPPER const & relPermWrapper,
+ DofNumberAccessor const & dofNumberAccessor,
+ ImmiscibleMultiphaseFlowAccessors const & multiPhaseFlowAccessors,
+ MultiphaseFluidAccessors const & fluidAccessors,
+ CapPressureAccessors const & capPressureAccessors,
+ PermeabilityAccessors const & permeabilityAccessors,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs,
+ integer const hasCapPressure,
+ integer const useTotalMassEquation,
+ integer const checkPhasePresenceInGravity,
+ string_array const & interfaceFaceSetNames,
+ stdVector< std::array< std::tuple< constitutive::RelativePermeabilityBase *,
+ constitutive::CapillaryPressureBase *,
+ constitutive::TwoPhaseImmiscibleFluid * >, 2 > > const & interfaceConstitutivePairs,
+ stdVector< std::array< localIndex, 2 > > const & interfacePairRegionIndices,
+ arrayView1d< localIndex const > const & interfaceRegionLookup,
+ arrayView1d< real64 > const & convergedPcInt,
+ localIndex const GEOS_UNUSED_PARAM( domainSize ) )
+ : Base( numPhases,
+ rankOffset,
+ stencilWrapper,
+ dofNumberAccessor,
+ multiPhaseFlowAccessors,
+ fluidAccessors,
+ capPressureAccessors,
+ permeabilityAccessors,
+ dt,
+ localMatrix,
+ localRhs,
+ hasCapPressure,
+ useTotalMassEquation,
+ checkPhasePresenceInGravity ),
+ // m_capPressureWrapper( capPressureWrapper ),
+ // m_relPermWrapper( relPermWrapper ),
+ m_interfaceFaceSetNames( interfaceFaceSetNames ),
+ m_interfaceConstitutivePairs( interfaceConstitutivePairs ),
+ m_interfacePairRegionIndices( interfacePairRegionIndices ),
+ m_interfaceRegionLookup( interfaceRegionLookup ),
+ m_convergedPcInt( convergedPcInt )
+ {}
+
+ /**
+ * @brief Compute the local flux contributions to the residual and Jacobian
+ * @tparam FUNC the type of the function that can be used to customize the computation of the flux
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ * @param[in] NoOpFunc the function used to customize the computation of the flux
+ */
+
+ template< typename FUNC = NoOpFunc > // should change to multiphase
+ GEOS_HOST_DEVICE
+ void computeFlux( localIndex const iconn,
+ StackVariables & stack,
+ FUNC && kernelOp = NoOpFunc{} ) const
+ {
+
+ bool connectorHasInterfaceConditionQ = false;
+ bool anyInterfaceConditionsQ = not m_interfaceConstitutivePairs.empty();
+ if( anyInterfaceConditionsQ )
+ {
+ connectorHasInterfaceConditionQ =
+ ( iconn < m_interfaceRegionLookup.size() && m_interfaceRegionLookup[iconn] >= 0 );
+ }
+
+
+
+ // if (connectorHasInterfaceConditionQ){
+ // // Improved transmission conditions
+ // int ammar_code = 0;
+ // }else{
+ // // Regular contribution
+ // int standard_code = 0;
+ // }
+
+ m_stencilWrapper.computeWeights( iconn,
+ m_permeability,
+ m_dPerm_dPres,
+ stack.transmissibility,
+ stack.dTrans_dPres );
+
+ localIndex k[2];
+ localIndex connectionIndex = 0;
+
+ // one-sided transmissibility
+ m_stencilWrapper.computeHalfWeights( iconn,
+ m_permeability,
+ m_dPerm_dPres,
+ stack.transmissibilityHat,
+ stack.dTransHat_dPres );
+
+
+
+ for( k[0] = 0; k[0] < stack.numFluxElems; ++k[0] )
+ {
+ for( k[1] = k[0] + 1; k[1] < stack.numFluxElems; ++k[1] )
+ {
+ // clear working arrays
+ real64 densMean[numEqn]{};
+ real64 dDensMean_dP[numEqn][2]{};
+
+ real64 presGrad[numEqn]{};
+ real64 dPresGrad_dP[numEqn][2]{};
+
+ real64 gravHead[numEqn]{};
+ real64 dGravHead_dP[numEqn][2]{};
+
+ real64 capGrad[numEqn]{};
+ // real64 capPresIC[numEqn][2]{};
+ // real64 jFMultiplier[numEqn][2]{};
+ real64 dCapGrad_dP[numEqn][2]{};
+ real64 dCapGrad_dS[numEqn][2]{};
+
+ real64 fluxVal[numEqn]{};
+ real64 dFlux_dP[numEqn][2]{};
+ real64 dFlux_dS[numEqn][2]{};
+
+ real64 mobility[numEqn]{};
+ real64 dMob_dP[numEqn][2]{};
+ real64 dMob_dS[numEqn][2]{};
+
+ real64 density2[numEqn]{};
+ real64 dDens_dP2[numEqn][2]{};
+ real64 viscosity[numEqn]{};
+ real64 dVisc_dP[numEqn][2]{};
+ real64 gravCoef2[numEqn]{};
+ real64 gravCoefHat[numEqn]{};
+
+ real64 uT = 0;
+ // real64 total_mobility = 0;
+ real64 duT_dP[numEqn]{};
+ real64 duT_dS[numEqn]{};
+
+ real64 potGrad_ip[numEqn]{};
+ real64 alpha_ip[numEqn]{};
+
+ real64 const trans[2] = { stack.transmissibility[connectionIndex][0], stack.transmissibility[connectionIndex][1] };
+ real64 const dTrans_dP[2] = { stack.dTrans_dPres[connectionIndex][0], stack.dTrans_dPres[connectionIndex][1] };
+
+ real64 const transHat[2] = { stack.transmissibilityHat[connectionIndex][0], stack.transmissibilityHat[connectionIndex][1] * -1.0};
+ real64 const dTransHat_dP[2] = { stack.dTransHat_dPres[connectionIndex][0], stack.dTransHat_dPres[connectionIndex][1] * -1.0};
+
+ // cell indices
+ localIndex const seri[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )};
+ localIndex const sesri[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )};
+ localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )};
+
+ stdVector< real64 > saturations = {m_phaseVolFrac[seri[0]][sesri[0]][sei[0]][0], m_phaseVolFrac[seri[1]][sesri[1]][sei[1]][0] };
+ stdVector< real64 > pressures = {m_pres[seri[0]][sesri[0]][sei[0]], m_pres[seri[1]][sesri[1]][sei[1]] };
+ // bool isJfunction = 0;
+
+ // loop over phases
+ for( integer ip = 0; ip < m_numPhases; ++ip )
+ {
+ // calculate quantities on primary connected cells
+ integer denom = 0;
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ // density
+ bool const phaseExists = (m_phaseVolFrac[seri[ke]][sesri[ke]][sei[ke]][ip] > 0);
+ if( m_checkPhasePresenceInGravity && !phaseExists )
+ {
+ continue;
+ }
+
+ real64 const density = m_dens[seri[ke]][sesri[ke]][sei[ke]][0][ip]; // r = rho1 || rho2
+ real64 const dDens_dP = m_dDens_dPres[seri[ke]][sesri[ke]][sei[ke]][0][ip][Deriv::dP]; // dr/dP = dr1/dP1 || dr2/dP
+ // average density and derivatives
+ densMean[ip] += density; // rho = (rho1 + rho2)
+ dDensMean_dP[ip][ke] = dDens_dP; // drho/dP = { (dr1/dP1) , (dr2/dP2) }
+ denom++;
+ }
+
+ if( denom > 1 )
+ {
+ densMean[ip] /= denom; // rho = (rho1 + rho2) / denom
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ dDensMean_dP[ip][ke] /= denom; // drho/dP = { (dr1/dP1) / denom , (dr2/dP2) / denom }
+ }
+ }
+
+ //***** calculation of flux *****
+
+ // compute potential difference
+ real64 potScale = 0.0;
+ real64 dPresGrad_dTrans = 0.0;
+ real64 dGravHead_dTrans = 0.0;
+ real64 dCapGrad_dTrans = 0.0;
+ gravCoefHat[0] = 0;
+ gravCoefHat[1] = 0;
+ constexpr int signPotDiff[2] = {1, -1};
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ localIndex const er = seri[ke];
+ localIndex const esr = sesri[ke];
+ localIndex const ei = sei[ke];
+
+ real64 const pressure = m_pres[er][esr][ei]; // P = P1 || P2
+ presGrad[ip] += trans[ke] * pressure; // DPv = T (P1 - P2)
+ dPresGrad_dTrans += signPotDiff[ke] * pressure; // dDPv/dT = (P1 - P2)
+ dPresGrad_dP[ip][ke] = trans[ke]; // dDPv/dP = { T , -T }
+
+ real64 const gravD = trans[ke] * m_gravCoef[er][esr][ei]; // D = T g z1 || -T g z2
+ real64 pot = trans[ke] * pressure - densMean[ip] * gravD; // Phi = T P1 - rho T g z1 || -T P2 + rho T g z2
+ gravCoefHat[0] += m_gravCoef[er][esr][ei] * 0.5;
+ gravCoefHat[1] += m_gravCoef[er][esr][ei] * 0.5;
+
+ gravCoef2[ke] = m_gravCoef[er][esr][ei];
+
+ gravHead[ip] += densMean[ip] * gravD; // DPg = rho (T g z1 - T g z2) = T rho g (z1 - z2)
+ dGravHead_dTrans += signPotDiff[ke] * densMean[ip] * m_gravCoef[er][esr][ei]; // dDPg/dT = rho g z1 - rho g z2 = rho g (z1 - z2)
+
+ for( integer i = 0; i < 2; ++i )
+ {
+ dGravHead_dP[ip][i] += dDensMean_dP[ip][i] * gravD; // dDPg/dP = {drho/dP1 * T g (z1 - z2) , drho/dP2 * T g (z1 - z2)}
+ }
+
+ if( m_hasCapPressure ) // check sign convention
+ {
+ real64 const capPres = m_phaseCapPressure[er][esr][ei][0][ip]; // Pc = Pc1 || Pc2
+ // jFMultiplier[ip][ke] = m_jFuncMultiplier[er][esr][ei][0];
+
+ // capPresIC[ip][ke] = capPres;
+ dCapGrad_dTrans -= signPotDiff[ke] * capPres; // dDPc/dT = (-Pc1 + Pc2)
+ pot -= trans[ke] * capPres; // Phi = T P1 - rho T g z1 - T Pc1 || -T P2 + rho T g z2 + T
+ // Pc2
+ capGrad[ip] -= trans[ke] * capPres; // DPc = T (-Pc1 + Pc2)
+ }
+
+ potScale = fmax( potScale, fabs( pot ) ); // maxPhi = Phi1 > Phi2 ? Phi1 : Phi2
+ }
+
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ dPresGrad_dP[ip][ke] += dTrans_dP[ke] * dPresGrad_dTrans; // dDPv/dP = { T + dT/dP1 * (P1 - P2) , -T + dT/dP2 * (P1 - P2)}
+ dGravHead_dP[ip][ke] += dTrans_dP[ke] * dGravHead_dTrans; // dDPg/dP = { drho/dP1 * T g (z1 - z2) + dT/dP1 * rho g (z1 - z2) ,
+ // drho/dP2 * T g (z1 - z2) + dT/dP2 * rho g (z1 - z2) }
+ if( m_hasCapPressure )
+ {
+ real64 const dCapPres_dS = m_dPhaseCapPressure_dPhaseVolFrac[seri[ke]][sesri[ke]][sei[ke]][0][ip][ip]; // dPc/dS = dPc1/dS1 ||
+ // dPc2/dS2
+ dCapGrad_dP[ip][ke] += dTrans_dP[ke] * dCapGrad_dTrans; // dDPc/dP = { dT/dP1 *
+ // (-Pc1 + Pc2) ,
+ // dT/dP2 *
+ // (-Pc1 + Pc2) }
+ dCapGrad_dS[ip][ke] -= trans[ke] * dCapPres_dS; // dDPc/dS = { -T *
+ // dPc1/dS1 , T *
+ // dPc2/dS2 }
+ }
+ }
+
+ // *** upwinding ***
+ // compute potential gradient
+ real64 potGrad = presGrad[ip] - gravHead[ip]; // DPhi = T (P1 - P2) - T rho g (z1 - z2)
+ if( m_hasCapPressure )
+ {
+ potGrad += capGrad[ip]; // DPhi = T (P1 - P2) - T rho g (z1 - z2) + T (-Pc1 + Pc2)
+ }
+
+ // compute upwinding tolerance
+ real64 constexpr upwRelTol = 1e-8;
+ real64 const upwAbsTol = fmax( potScale * upwRelTol, LvArray::NumericLimits< real64 >::epsilon ); // abstol = maxPhi * tol > eps ?
+ // maxPhi * tol : eps
+
+ // decide mobility coefficients - smooth variation in [-upwAbsTol; upwAbsTol]
+ real64 alpha = ( potGrad + upwAbsTol ) / ( 2 * upwAbsTol ); // alpha = (DPhi + abstol) / abstol / 2
+
+ // choose upstream cell
+ if( alpha <= 0.0 || alpha >= 1.0 ) // no smoothing needed
+ {
+ localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) ); // 1 upwind -> k_up = 0 || 2 upwind -> k_up = 1
+
+ mobility[ip] = m_mob[seri[k_up]][sesri[k_up]][sei[k_up]][ip]; // M = Mupstream
+ density2[ip] = m_dens[seri[k_up]][sesri[k_up]][sei[k_up]][0][ip]; // r = rho1 || rho2
+ dDens_dP2[ip][k_up] = m_dDens_dPres[seri[k_up]][sesri[k_up]][sei[k_up]][0][ip][Deriv::dP]; // dr/dP = dr1/dP1 || dr2/dP
+ viscosity[ip] = m_visc[seri[k_up]][sesri[k_up]][sei[k_up]][0][ip];
+ dVisc_dP[ip][k_up] = m_dVisc_dPres[seri[k_up]][sesri[k_up]][sei[k_up]][0][ip][Deriv::dP];
+ dMob_dP[ip][k_up] = m_dMob[seri[k_up]][sesri[k_up]][sei[k_up]][ip][Deriv::dP]; // dM/dP = {dM/dP1 , 0} OR {0 , dM/dP2}
+ dMob_dS[ip][k_up] = m_dMob[seri[k_up]][sesri[k_up]][sei[k_up]][ip][Deriv::dS]; // dM/dS = {dM/dS1 , 0} OR {0 , dM/dS2}
+ }
+ else // perform smoothing
+ {
+ real64 const mobWeights[2] = { alpha, 1.0 - alpha };
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ mobility[ip] += mobWeights[ke] * m_mob[seri[ke]][sesri[ke]][sei[ke]][ip]; // M = alpha * M1 + (1 - alpha) * M2
+ density2[ip] += mobWeights[ke] * m_dens[seri[ke]][sesri[ke]][sei[ke]][0][ip]; // r = rho1 || rho2
+ dDens_dP2[ip][ke] = mobWeights[ke] * m_dDens_dPres[seri[ke]][sesri[ke]][sei[ke]][0][ip][Deriv::dP]; // dr/dP = dr1/dP1 ||
+ // dr2/dP
+ viscosity[ip] = m_visc[seri[ke]][sesri[ke]][sei[ke]][0][ip];
+ dVisc_dP[ip][ke] = m_dVisc_dPres[seri[ke]][sesri[ke]][sei[ke]][0][ip][Deriv::dP];
+ dMob_dP[ip][ke] = mobWeights[ke] * m_dMob[seri[ke]][sesri[ke]][sei[ke]][ip][Deriv::dP]; // dM/dP = {alpha * dM1/dP1 , (1 -
+ // alpha) * dM2/dP2}
+ dMob_dS[ip][ke] = mobWeights[ke] * m_dMob[seri[ke]][sesri[ke]][sei[ke]][ip][Deriv::dS]; // dM/dP = {alpha * dM1/dS1 , (1 -
+ // alpha) * dM2/dS2}
+ }
+ }
+
+ // pressure gradient depends on all points in the stencil
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ dFlux_dP[ip][ke] += dPresGrad_dP[ip][ke]; // dF/dP = { T + dT/dP1 * (P1 - P2) ,
+ // -T + dT/dP2 * (P1 - P2) }
+ }
+
+ // gravitational head depends only on the two cells connected (same as mean density)
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ dFlux_dP[ip][ke] -= dGravHead_dP[ip][ke]; // dF/dP = { T + dT/dP1 * (P1 - P2) - drho/dP1 * T g (z1 - z2) - dT/dP1 * rho g (z1 -
+ // z2) ,
+ // -T + dT/dP2 * (P1 - P2) - drho/dP2 * T g (z1 - z2) - dT/dP2 * rho g (z1 -
+ // z2) }
+ }
+
+ // capillary pressure contribution
+ if( m_hasCapPressure )
+ {
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ dFlux_dP[ip][ke] += dCapGrad_dP[ip][ke]; // dF/dP = { T + dT/dP1 * (P1 - P2) - drho/dP1 * T g (z1 - z2) - dT/dP1 * rho g (z1
+ // - z2) + dT/dP1 * (-Pc1 + Pc2) ,
+ // -T + dT/dP2 * (P1 - P2) - drho/dP2 * T g (z1 - z2) - dT/dP2 * rho g (z1
+ // - z2) + dT/dP2 * (-Pc1 + Pc2) }
+
+ dFlux_dS[ip][ke] += dCapGrad_dS[ip][ke]; // dF/dS = { T * -dPc/dS1 , T * dPc/dS2 }
+ }
+ }
+
+ // compute the flux and derivatives using upstream cell mobility
+ fluxVal[ip] = mobility[ip] * potGrad; // F = M * DPhi
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ dFlux_dP[ip][ke] *= mobility[ip]; // dF/dP = { M [ T + dT/dP1 * (P1 - P2) - drho/dP1 * T g (z1 - z2) - dT/dP1 * rho g (z1 -
+ // z2) + dT/dP1 * (-Pc1 + Pc2)] ,
+ // M [-T + dT/dP2 * (P1 - P2) - drho/dP2 * T g (z1 - z2) - dT/dP2 * rho g (z1 -
+ // z2) + dT/dP2 * (-Pc1 + Pc2)] }
+
+ dFlux_dS[ip][ke] *= mobility[ip]; // dF/dS = { M [T * -dPc/dS1] , M [T * dPc/dS2] }
+ }
+
+ // add contribution from upstream cell mobility derivatives
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+
+ real64 dMob_dP2 = mobility[ip] / density2[ip] * (-dVisc_dP[ip][ke] / viscosity[ip]);
+
+ duT_dP[ke] += dFlux_dP[ip][ke] / density2[ip] + dMob_dP2 * potGrad;
+
+ dFlux_dP[ip][ke] += dMob_dP[ip][ke] * potGrad; // dF/dP = { M [ T + dT/dP1 * (P1 - P2) - drho1/dP * T g (z1 - z2) - dT/dP1 *
+ // rho g (z1 - z2) + dT/dP1 * (-Pc1 + Pc2)] + dM/dP1 * DPhi ,
+ // M [-T + dT/dP2 * (P1 - P2) - drho2/dP * T g (z1 - z2) - dT/dP2 *
+ // rho g (z1 - z2) + dT/dP2 * (-Pc1 + Pc2)] + dM/dP2 * DPhi }
+ dFlux_dS[ip][ke] += dMob_dS[ip][ke] * potGrad; // dF/dS = { M [T * -dPc/dS1] + dM/dS1 * DPhi , M [T * dPc/dS2] + dM/dS2 * DPhi
+ // }
+ }
+
+
+ uT += fluxVal[ip] / density2[ip];
+
+ // add contribution from upstream cell mobility derivatives
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+// duT_dP[ke] += dFlux_dP[ip][ke] - fluxVal[ip] * dDens_dP2[ip][ke] / density2[ip];
+// // duT_dP[ke] += dFlux_dP[ip][ke];
+
+// duT_dP[ke] /= density2[ip];
+
+ duT_dS[ke] += dFlux_dS[ip][ke] / density2[ip];
+ // duT_dS[ke] += dFlux_dS[ip][ke];
+
+ }
+
+ potGrad_ip[ip] = potGrad;
+ alpha_ip[ip] = alpha;
+
+ } // loop over phases
+
+
+ // this determines whether the local solver is needed becuase of heterogeneous capillary pressure regions
+ // bool notOnInterface = std::fabs( jFMultiplier[0][0] - jFMultiplier[0][1] ) < 1 && std::fabs( jFMultiplier[1][0] -
+ // jFMultiplier[1][1] ) < 1;
+ bool notOnInterface = !connectorHasInterfaceConditionQ;
+ if( notOnInterface )
+ {
+ for( integer ip = 0; ip < 2; ++ip )
+ {
+ // populate local flux vector and derivatives
+ stack.localFlux[k[0]*numEqn + ip] += m_dt * fluxVal[ip];
+ stack.localFlux[k[1]*numEqn + ip] -= m_dt * fluxVal[ip];
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ // pressure
+ localIndex const localDofIndexPres = k[ke] * numDof;
+ stack.localFluxJacobian[k[0]*numEqn + ip][localDofIndexPres] += m_dt * dFlux_dP[ip][ke];
+ stack.localFluxJacobian[k[1]*numEqn + ip][localDofIndexPres] -= m_dt * dFlux_dP[ip][ke];
+
+ // saturation
+ localIndex const localDofIndexSat = k[ke] * numDof + 1;
+ stack.localFluxJacobian[k[0]*numEqn + ip][localDofIndexSat] += m_dt * dFlux_dS[ip][ke];
+ stack.localFluxJacobian[k[1]*numEqn + ip][localDofIndexSat] -= m_dt * dFlux_dS[ip][ke];
+ }
+
+ // Customize the kernel with this lambda
+ kernelOp( k, seri, sesri, sei, connectionIndex, alpha_ip[ip], mobility, potGrad_ip[ip], fluxVal, dFlux_dP, dFlux_dS );
+
+ }
+ }
+ else
+ {
+
+
+ bool converged = 0;
+
+
+ // clear working arrays
+ real64 halfFluxVal[numEqn][2]{};
+ // real64 dhalfFlux1_dP[numEqn][2]{};
+ // real64 dhalfFlux1_dS[numEqn][2]{};
+ // real64 dhalfFlux2_dP[numEqn][2]{};
+ // real64 dhalfFlux2_dS[numEqn][2]{};
+ // real64 dhalfFlux_duT[numEqn][2]{};
+ // real64 dhalfFlux_dpc[numEqn][2]{};
+
+
+ // stdVector< real64 > JFMultipliers = {jFMultiplier[0][0], jFMultiplier[0][1]};
+ stdVector< real64 > JFMultipliers = {0.0, 0.0};
+ // trappedSats will be extracted from models below and passed to local_solver
+ stdVector< real64 > trappedSats1 = {0.0, 0.0};
+ stdVector< real64 > trappedSats2 = {0.0, 0.0};
+ stdVector< fields::cappres::ModeIndexType > modes = {static_cast< fields::cappres::ModeIndexType >(0), static_cast< fields::cappres::ModeIndexType >(0)};
+ stdVector< real64 > transHats = {transHat[0], transHat[1]};
+ stdVector< real64 > dTransHats_dP = {dTransHat_dP[0], dTransHat_dP[1]};
+ stdVector< real64 > gravCoefHats = {gravCoefHat[0], gravCoefHat[1]};
+ stdVector< real64 > gravCoefs = {gravCoef2[0], gravCoef2[1]};
+ stdVector< real64 > cellCenterDuTdS = {duT_dP[0], duT_dP[1], duT_dS[0], duT_dS[1]};
+ stdVector< real64 > cellCenterDens = {density2[0], density2[1]};
+ stdVector< real64 > cellCenterDens_dP = {dDens_dP2[0][0], dDens_dP2[0][1], dDens_dP2[1][0], dDens_dP2[1][1]};
+ // std::vector< RelativePermeabilityBase * > relPerms = {std::get< 0 >( m_interfaceConstitutivePairs_temp ), std::get< 0 >(
+ // m_interfaceConstitutivePairs_temp )};
+ // std::vector< CapillaryPressureBase * > capPressures = {std::get< 1 >( m_interfaceConstitutivePairs_temp ), std::get< 1 >(
+ // m_interfaceConstitutivePairs_temp )};
+ // std::vector< TwoPhaseImmiscibleFluid * > fluids = {std::get< 2 >( m_interfaceConstitutivePairs_temp ), std::get< 2 >(
+ // m_interfaceConstitutivePairs_temp )};
+
+ // auto const & pairArray = m_interfaceConstitutivePairs[0];
+ localIndex const surfaceRegionIndex = m_interfaceRegionLookup[iconn];
+ auto const & pairArray = m_interfaceConstitutivePairs[surfaceRegionIndex];
+ auto const & pairReg = m_interfacePairRegionIndices[surfaceRegionIndex];
+
+// Determine canonical ordering based on global DOF numbers.
+// Always put the cell with the SMALLER global DOF as local_solver side 0.
+// This guarantees both ranks process the same interface connection identically,
+// since local_solver is NOT symmetric w.r.t. swapping its two sides.
+ globalIndex const dof0 = m_dofNumber[seri[0]][sesri[0]][sei[0]];
+ globalIndex const dof1 = m_dofNumber[seri[1]][sesri[1]][sei[1]];
+
+// p[i] maps canonical side i to stencil index (0 or 1)
+ localIndex p[2] = {0, 1}; // default: stencil cell 0 has smaller DOF
+ if( dof0 > dof1 )
+ {
+ // Stencil cell 1 has smaller DOF — swap to make it canonical side 0
+ p[0] = 1;
+ p[1] = 0;
+ }
+
+// Build local_solver inputs using mapped indices so that
+// canonical side 0 always has the smaller global DOF
+
+// uT is defined as flow from stencil cell 0 to stencil cell 1.
+// If we swapped the cells, the direction reverses.
+// duT derivatives must also be negated and cell-index-swapped.
+ real64 const uT_sign = (p[0] == 0) ? 1.0 : -1.0;
+ real64 const uT_ls = uT_sign * uT;
+
+ stdVector< real64 > saturations_ls = {saturations[p[0]], saturations[p[1]]};
+ stdVector< real64 > pressures_ls = {pressures[p[0]], pressures[p[1]]};
+// transHat sign convention: transHat[0]=+T_0, transHat[1]=-T_1.
+// When stencil is reversed, swap and negate to maintain: ls[0]=+T_canon0, ls[1]=-T_canon1
+ stdVector< real64 > transHats_ls = {uT_sign * transHats[p[0]], uT_sign * transHats[p[1]]};
+ stdVector< real64 > dTransHats_dP_ls = {uT_sign * dTransHats_dP[p[0]], uT_sign * dTransHats_dP[p[1]]};
+ stdVector< real64 > gravCoefHats_ls = {gravCoefHats[p[0]], gravCoefHats[p[1]]};
+ stdVector< real64 > gravCoefs_ls = {gravCoefs[p[0]], gravCoefs[p[1]]};
+ stdVector< real64 > cellCenterDuTdS_ls = {uT_sign * cellCenterDuTdS[p[0]], uT_sign * cellCenterDuTdS[p[1]],
+ uT_sign * cellCenterDuTdS[2 + p[0]], uT_sign * cellCenterDuTdS[2 + p[1]]};
+ stdVector< real64 > cellCenterDens_ls = {cellCenterDens[p[0]], cellCenterDens[p[1]]};
+ stdVector< real64 > cellCenterDens_dP_ls = {cellCenterDens_dP[p[0]], cellCenterDens_dP[p[1]],
+ cellCenterDens_dP[2 + p[0]], cellCenterDens_dP[2 + p[1]]};
+
+// Map sei indices for extracting per-element constitutive data.
+// sei_ls[ke] is the element index for canonical side ke.
+ localIndex const sei_ls[2] = {sei[p[0]], sei[p[1]]};
+
+// Match constitutive models from the pair to the canonical ordering.
+// pairArray[0] corresponds to pairReg[0], pairArray[1] to pairReg[1].
+// Canonical side 0 is stencil cell p[0] with region seri[p[0]].
+// We need to find which pair side matches each canonical side's region.
+ localIndex cp[2] = {0, 1}; // cp[i] = which pair side goes with canonical side i
+ if( pairReg[0] >= 0 && pairReg[1] >= 0 )
+ {
+ localIndex const canonReg0 = seri[p[0]]; // region of canonical side 0
+ if( canonReg0 == pairReg[1] )
+ {
+ // canonical side 0's region matches pair side 1
+ cp[0] = 1;
+ cp[1] = 0;
+ }
+ }
+
+ std::vector< constitutive::RelativePermeabilityBase * > relPerms = {
+ std::get< 0 >( pairArray[cp[0]] ),
+ std::get< 0 >( pairArray[cp[1]] )
+ };
+
+ std::vector< constitutive::CapillaryPressureBase * > capPressures = {
+ std::get< 1 >( pairArray[cp[0]] ),
+ std::get< 1 >( pairArray[cp[1]] )
+ };
+
+ std::vector< constitutive::TwoPhaseImmiscibleFluid * > fluids = {
+ std::get< 2 >( pairArray[cp[0]] ),
+ std::get< 2 >( pairArray[cp[1]] )
+ };
+
+ // Extract historical volume fractions, trapped saturations, and mode from TableCapillaryPressureHysteresis models
+ // Initialize with sentinel values to indicate they haven't been set
+ // Use -1.0 as a sentinel value (invalid for saturations which are 0-1)
+ stdVector< real64 > phaseMaxHistoricalVolFraction1 = {-1.0, -1.0};
+ stdVector< real64 > phaseMinHistoricalVolFraction1 = {-1.0, -1.0};
+ stdVector< real64 > phaseMaxHistoricalVolFraction2 = {-1.0, -1.0};
+ stdVector< real64 > phaseMinHistoricalVolFraction2 = {-1.0, -1.0};
+
+ // Trapped saturations are available in all capillary pressure models (via base class),
+ // but we only extract them when using hysteresis models since they're most meaningful there
+ // Initialize with sentinel values to indicate they haven't been set
+ stdVector< real64 > trappedSats1_extracted = {-1.0, -1.0};
+ stdVector< real64 > trappedSats2_extracted = {-1.0, -1.0};
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ constitutive::TableCapillaryPressureHysteresis * capPresHyst =
+ dynamic_cast< constitutive::TableCapillaryPressureHysteresis * >(capPressures[ke]);
+
+ if( capPresHyst != nullptr )
+ {
+ // Get the mode for this cell
+ auto const & modeArray = capPresHyst->getField< fields::cappres::mode >().reference();
+ if( sei_ls[ke] < static_cast< localIndex >(modeArray.size()) )
+ {
+ modes[ke] = static_cast< fields::cappres::ModeIndexType >(modeArray[sei_ls[ke]]);
+ }
+
+ // Get historical volume fractions for this cell
+ auto const & maxHistArray = capPresHyst->getField< fields::cappres::phaseMaxHistoricalVolFraction >().reference();
+ auto const & minHistArray = capPresHyst->getField< fields::cappres::phaseMinHistoricalVolFraction >().reference();
+
+ if( sei_ls[ke] < static_cast< localIndex >(maxHistArray.size( 0 )) && m_numPhases > 0 )
+ {
+ for( integer ip = 0; ip < m_numPhases; ++ip )
+ {
+ if( ke == 0 )
+ {
+ phaseMaxHistoricalVolFraction1[ip] = maxHistArray[sei_ls[ke]][ip];
+ phaseMinHistoricalVolFraction1[ip] = minHistArray[sei_ls[ke]][ip];
+ }
+ else
+ {
+ phaseMaxHistoricalVolFraction2[ip] = maxHistArray[sei_ls[ke]][ip];
+ phaseMinHistoricalVolFraction2[ip] = minHistArray[sei_ls[ke]][ip];
+ }
+ }
+ }
+
+ // Get trapped volume fractions for this cell
+ // Note: phaseTrappedVolFraction is available in all capillary pressure models (via base class)
+ auto const & trappedArray = capPresHyst->getField< fields::cappres::phaseTrappedVolFraction >().reference();
+
+ if( sei_ls[ke] < static_cast< localIndex >(trappedArray.size( 0 )) && m_numPhases > 0 )
+ {
+ for( integer ip = 0; ip < m_numPhases; ++ip )
+ {
+ if( ke == 0 )
+ {
+ trappedSats1_extracted[ip] = trappedArray[sei_ls[ke]][0][ip]; // [element][subregion][phase]
+ }
+ else
+ {
+ trappedSats2_extracted[ip] = trappedArray[sei_ls[ke]][0][ip];
+ }
+ }
+ }
+ }
+ else
+ {
+ // For non-hysteresis models, we can still try to get trapped saturations if available
+ // but they're typically not meaningful for non-hysteresis models
+ // We'll extract them anyway in case they were set (e.g., for consistency)
+ auto const & trappedArray = capPressures[ke]->getField< fields::cappres::phaseTrappedVolFraction >().reference();
+
+ if( sei_ls[ke] < static_cast< localIndex >(trappedArray.size( 0 )) && m_numPhases > 0 )
+ {
+ for( integer ip = 0; ip < m_numPhases; ++ip )
+ {
+ if( ke == 0 )
+ {
+ trappedSats1_extracted[ip] = trappedArray[sei_ls[ke]][0][ip];
+ }
+ else
+ {
+ trappedSats2_extracted[ip] = trappedArray[sei_ls[ke]][0][ip];
+ }
+ }
+ }
+ }
+ }
+
+ stdVector< real64 > phi = {halfFluxVal[0][0], halfFluxVal[0][1]};
+ stdVector< real64 > grad_phi_P = {0.0, 0.0, 0.0, 0.0};
+ stdVector< real64 > grad_phi_S = {0.0, 0.0, 0.0, 0.0};
+
+
+ // Use extracted trapped saturations if available, otherwise use defaults
+ if( trappedSats1_extracted[0] >= 0.0 )
+ {
+ trappedSats1 = trappedSats1_extracted;
+ }
+ if( trappedSats2_extracted[0] >= 0.0 )
+ {
+ trappedSats2 = trappedSats2_extracted;
+ }
+
+ real64 warmStartPc = ( iconn < m_convergedPcInt.size() )
+ ? m_convergedPcInt[iconn] : -1.0;
+
+ local_solver( uT_ls, saturations_ls, pressures_ls, JFMultipliers, trappedSats1, trappedSats2, modes, transHats_ls, dTransHats_dP_ls, gravCoefHats_ls, gravCoefs_ls,
+ cellCenterDuTdS_ls, cellCenterDens_ls, cellCenterDens_dP_ls, relPerms, capPressures, fluids, phi, grad_phi_P, grad_phi_S, converged,
+ phaseMaxHistoricalVolFraction1, phaseMinHistoricalVolFraction1, phaseMaxHistoricalVolFraction2, phaseMinHistoricalVolFraction2,
+ warmStartPc );
+
+ if( iconn < m_convergedPcInt.size() )
+ {
+ m_convergedPcInt[iconn] = warmStartPc;
+ }
+
+ // Remap local_solver outputs back to stencil ordering for global assembly.
+ // local_solver returns phi[0]=flux(phase0), phi[1]=flux(phase1) (phase-indexed).
+ // grad_phi_P layout: [0]=dFlux0/dP_canon0, [1]=dFlux0/dP_canon1,
+ // [2]=dFlux1/dP_canon0, [3]=dFlux1/dP_canon1.
+ // We need to remap canonical cell indices back to stencil cell indices.
+ // If canonical ordering differs from stencil ordering (p[0]==1), negate fluxes
+ // (direction reversal) and swap cell derivative indices.
+
+ if( p[0] == 0 )
+ {
+ // No swap needed - stencil ordering matches canonical ordering
+ fluxVal[0] = phi[0];
+ fluxVal[1] = phi[1];
+ dFlux_dP[0][0] = grad_phi_P[0];
+ dFlux_dP[0][1] = grad_phi_P[1];
+ dFlux_dP[1][0] = grad_phi_P[2];
+ dFlux_dP[1][1] = grad_phi_P[3];
+ dFlux_dS[0][0] = grad_phi_S[0];
+ dFlux_dS[0][1] = grad_phi_S[1];
+ dFlux_dS[1][0] = grad_phi_S[2];
+ dFlux_dS[1][1] = grad_phi_S[3];
+ }
+ else
+ {
+ // Stencil ordering is reversed relative to canonical.
+ // Negate fluxes (direction reversal) and swap cell derivative indices.
+ // Canon side 0 -> stencil cell 1, canon side 1 -> stencil cell 0
+ fluxVal[0] = -phi[0];
+ fluxVal[1] = -phi[1];
+ // dFlux/dP: swap cell indices and negate
+ dFlux_dP[0][0] = -grad_phi_P[1]; // dFlux0/dP_stencil0 = -dFlux0/dP_pair1
+ dFlux_dP[0][1] = -grad_phi_P[0]; // dFlux0/dP_stencil1 = -dFlux0/dP_pair0
+ dFlux_dP[1][0] = -grad_phi_P[3]; // dFlux1/dP_stencil0 = -dFlux1/dP_pair1
+ dFlux_dP[1][1] = -grad_phi_P[2]; // dFlux1/dP_stencil1 = -dFlux1/dP_pair0
+ dFlux_dS[0][0] = -grad_phi_S[1];
+ dFlux_dS[0][1] = -grad_phi_S[0];
+ dFlux_dS[1][0] = -grad_phi_S[3];
+ dFlux_dS[1][1] = -grad_phi_S[2];
+ }
+
+ // Global residual and jacobian update:
+ for( integer ip = 0; ip < m_numPhases; ++ip )
+ {
+ // populate local flux vector and derivatives
+ stack.localFlux[k[0]*numEqn + ip] += m_dt * fluxVal[ip];
+ stack.localFlux[k[1]*numEqn + ip] -= m_dt * fluxVal[ip];
+
+ for( integer ke = 0; ke < 2; ++ke )
+ {
+ // pressure
+ localIndex const localDofIndexPres = k[ke] * numDof;
+ stack.localFluxJacobian[k[0]*numEqn + ip][localDofIndexPres] += m_dt * dFlux_dP[ip][ke];
+ stack.localFluxJacobian[k[1]*numEqn + ip][localDofIndexPres] -= m_dt * dFlux_dP[ip][ke];
+
+ // saturation
+ localIndex const localDofIndexSat = k[ke] * numDof + 1;
+ stack.localFluxJacobian[k[0]*numEqn + ip][localDofIndexSat] += m_dt * dFlux_dS[ip][ke];
+ stack.localFluxJacobian[k[1]*numEqn + ip][localDofIndexSat] -= m_dt * dFlux_dS[ip][ke];
+ }
+
+ // Customize the kernel with this lambda
+ kernelOp( k, seri, sesri, sei, connectionIndex, alpha_ip[ip], mobility, potGrad_ip[ip], fluxVal, dFlux_dP, dFlux_dS );
+
+ } // loop over phases
+ } // end of else for interface conditions
+
+ connectionIndex++;
+ }
+ } // loop over connection elements
+ }
+
+protected:
+
+ /// Reference to the capillary pressure wrapper
+ // CAPPRESWRAPPER const m_capPressureWrapper;
+ // RELPERMWRAPPER const m_relPermWrapper;
+ string_array const m_interfaceFaceSetNames;
+ stdVector< std::array< std::tuple< constitutive::RelativePermeabilityBase *,
+ constitutive::CapillaryPressureBase *,
+ constitutive::TwoPhaseImmiscibleFluid * >, 2 > > const m_interfaceConstitutivePairs;
+ /// Region indices for each side of the interface pair (used for ordering consistency)
+ stdVector< std::array< localIndex, 2 > > const m_interfacePairRegionIndices;
+ arrayView1d< localIndex const > const m_interfaceRegionLookup;
+
+ /// Per-instance warm-start capillary pressure array (one entry per connection)
+ arrayView1d< real64 > const m_convergedPcInt;
+
+};
+
+
+
+/****************************************** */
+
+/**
+ * @class FluxComputeKernelFactory
+ */
+class FluxComputeKernelFactory
+{
+public:
+
+ /**
+ * @brief Create a new kernel and launch
+ * @tparam POLICY the policy used in the RAJA kernel
+ * @tparam STENCILWRAPPER the type of the stencil wrapper
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] dofKey string to get the element degrees of freedom numbers
+ * @param[in] solverName name of the solver (to name accessors)
+ * @param[in] elemManager reference to the element region manager
+ * @param[in] stencilWrapper reference to the stencil wrapper
+ * @param[in] dt time step size
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
template< typename POLICY, typename STENCILWRAPPER >
static void
createAndLaunch( integer const numPhases,
@@ -788,6 +3848,85 @@ class FluxComputeKernelFactory
checkPhasePresenceInGravity );
kernelType::template launch< POLICY >( stencilWrapper.size(), kernel );
}
+
+ /**
+ * @brief Create a new kernel and launch
+ * @tparam POLICY the policy used in the RAJA kernel
+ * @tparam STENCILWRAPPER the type of the stencil wrapper
+ * @tparam CAPPRESWRAPPER the type of the capillary pressure wrapper
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] dofKey string to get the element degrees of freedom numbers
+ * @param[in] solverName name of the solver (to name accessors)
+ * @param[in] elemManager reference to the element region manager
+ * @param[in] stencilWrapper reference to the stencil wrapper
+ * @param[in] capPresWrapper reference to the capillary pressure wrapper
+ * @param[in] dt time step size
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ * @param[inout] convergedPcInt warm-start capillary pressure array (one entry per connection),
+ * populated by the caller using global face indices for MPI invariance
+ */
+ // template< typename POLICY, typename STENCILWRAPPER, typename CAPPRESWRAPPER, typename RELPERMWRAPPER >
+ template< typename POLICY, typename STENCILWRAPPER >
+ static void
+ createAndLaunch( integer const numPhases,
+ globalIndex const rankOffset,
+ string const & dofKey,
+ integer const hasCapPressure,
+ integer const useTotalMassEquation,
+ integer const checkPhasePresenceInGravity,
+ string const & solverName,
+ ElementRegionManager const & elemManager,
+ STENCILWRAPPER const & stencilWrapper,
+ // CAPPRESWRAPPER const & capPresWrapper,
+ // RELPERMWRAPPER const & relPermWrapper,
+ string_array const & interfaceFaceSetNames,
+ stdVector< std::array< std::tuple< constitutive::RelativePermeabilityBase *,
+ constitutive::CapillaryPressureBase *,
+ constitutive::TwoPhaseImmiscibleFluid * >, 2 > > const & interfaceConstitutivePairs,
+ stdVector< std::array< localIndex, 2 > > const & interfacePairRegionIndices,
+ unordered_map< localIndex, localIndex > const & interfaceRegionByConnector,
+ ElementSubRegionBase const & subRegion,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs,
+ arrayView1d< real64 > const & convergedPcInt )
+ {
+ integer constexpr NUM_EQN = 2;
+ integer constexpr NUM_DOF = 2;
+ localIndex const domainSize = subRegion.size();
+ localIndex const numConn = stencilWrapper.size();
+
+ // Pre-compute the interface region lookup as a flat array for parallel-safe access.
+ // This replaces unordered_map::find/at inside the parallel kernel, which is not thread-safe.
+ array1d< localIndex > interfaceRegionLookup( numConn );
+ interfaceRegionLookup.setValues< serialPolicy >( -1 );
+ for( auto const & entry : interfaceRegionByConnector )
+ {
+ if( entry.first < numConn )
+ {
+ interfaceRegionLookup[entry.first] = entry.second;
+ }
+ }
+
+ ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor =
+ elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey );
+ dofNumberAccessor.setName( solverName + "/accessors/" + dofKey );
+
+ using kernelType = FluxComputeInterfaceConditionKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >;
+ typename kernelType::ImmiscibleMultiphaseFlowAccessors flowAccessors( elemManager, solverName );
+ typename kernelType::MultiphaseFluidAccessors fluidAccessors( elemManager, solverName );
+ typename kernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName );
+ typename kernelType::PermeabilityAccessors permAccessors( elemManager, solverName );
+
+ kernelType kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor,
+ flowAccessors, fluidAccessors, capPressureAccessors, permAccessors,
+ dt, localMatrix, localRhs, hasCapPressure, useTotalMassEquation,
+ checkPhasePresenceInGravity, interfaceFaceSetNames, interfaceConstitutivePairs,
+ interfacePairRegionIndices,
+ interfaceRegionLookup.toViewConst(), convergedPcInt, domainSize );
+ kernelType::template launch< POLICY >( numConn, kernel );
+ }
};
@@ -795,7 +3934,7 @@ class FluxComputeKernelFactory
enum class KernelFlags
{
- TotalMassEquation = 1 << 0, // 1
+ TotalMassEquation = 1 << 0, // 1
/// Add more flags like that if needed:
// Flag2 = 1 << 1, // 2
@@ -1421,7 +4560,7 @@ class ResidualNormKernelFactory
{
ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm );
}
- else // L2 norm
+ else // L2 norm
{
ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer );
}
@@ -1431,9 +4570,9 @@ class ResidualNormKernelFactory
-} // namespace immiscible multiphasekernels
+} // namespace immiscible multiphasekernels
-} // namespace geos
+} // namespace geos
-#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_MULTIPHASEKERNELS_HPP
+ #endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_MULTIPHASEKERNELS_HPP
diff --git a/src/coreComponents/schema/schema.xsd.other b/src/coreComponents/schema/schema.xsd.other
index fc732d195f6..1e92f909b5e 100644
--- a/src/coreComponents/schema/schema.xsd.other
+++ b/src/coreComponents/schema/schema.xsd.other
@@ -3267,6 +3267,10 @@ A field can represent a physical variable. (pressure, temperature, global compos
+
+
+
+
@@ -3276,7 +3280,11 @@ A field can represent a physical variable. (pressure, temperature, global compos
+<<<<<<< HEAD
+=======
+
+>>>>>>> Killough-PC_copy
diff --git a/src/docs/doxygen/GeosxConfig.hpp b/src/docs/doxygen/GeosxConfig.hpp
index 21b976a0d4c..a28bf2ae4ce 100644
--- a/src/docs/doxygen/GeosxConfig.hpp
+++ b/src/docs/doxygen/GeosxConfig.hpp
@@ -144,7 +144,7 @@
#define adiak_VERSION ..
/// Version information for caliper
-#define caliper_VERSION 2.8.0
+#define caliper_VERSION 2.4.0
/// Version information for Metis
#define metis_VERSION 5.1.0