diff --git a/.gitmodules b/.gitmodules
index 5552178f5ce..b2e33109a09 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,3 +10,6 @@
[submodule "src/coreComponents/fileIO/coupling/hdf5_interface"]
path = src/coreComponents/fileIO/coupling/hdf5_interface
url = ../../GEOS-DEV/hdf5_interface.git
+[submodule "src/coreComponents/constitutive/HPCReact"]
+ path = src/coreComponents/constitutive/HPCReact
+ url = git@github.com:GEOS-DEV/HPCReact.git
diff --git a/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_base.xml b/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_base.xml
new file mode 100644
index 00000000000..0f79543cf3a
--- /dev/null
+++ b/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_base.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_explicitUpdate_1DBar.xml b/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_explicitUpdate_1DBar.xml
new file mode 100644
index 00000000000..d33afd9f178
--- /dev/null
+++ b/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_explicitUpdate_1DBar.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_initialAggregate.xml b/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_initialAggregate.xml
new file mode 100644
index 00000000000..1d5feb21230
--- /dev/null
+++ b/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_initialAggregate.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_initialPrimaryConc.xml b/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_initialPrimaryConc.xml
new file mode 100644
index 00000000000..8ce64e0159d
--- /dev/null
+++ b/inputFiles/chemoMechanics/ChemoMechanics_CarbonateSystem_initialPrimaryConc.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystemPorosityUpdate_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystemPorosityUpdate_base.xml
new file mode 100644
index 00000000000..fd414cd5ba2
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystemPorosityUpdate_base.xml
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystemPorosityUpdate_main.xml b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystemPorosityUpdate_main.xml
new file mode 100644
index 00000000000..26074ddb384
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystemPorosityUpdate_main.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_base.xml
new file mode 100644
index 00000000000..7ef7360e004
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_base.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_initialAggregate.xml b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_initialAggregate.xml
new file mode 100644
index 00000000000..767b9387978
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_initialAggregate.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_initialPrimaryConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_initialPrimaryConc.xml
new file mode 100644
index 00000000000..9fe0e5abeae
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_initialPrimaryConc.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_logConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_logConc.xml
new file mode 100644
index 00000000000..da291b97da0
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_logConc.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_main.xml b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_main.xml
new file mode 100644
index 00000000000..3d6a6de7754
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/1DCarbonateSystem/mixedReactionCarbonateSystem_main.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_allKinetic_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_allKinetic_base.xml
new file mode 100644
index 00000000000..27df60a6124
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_allKinetic_base.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_allKinetic_main.xml b/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_allKinetic_main.xml
new file mode 100644
index 00000000000..d2d3be7c2b1
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_allKinetic_main.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_base.xml
new file mode 100644
index 00000000000..4bc502df425
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_base.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_initialAggregate.xml b/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_initialAggregate.xml
new file mode 100644
index 00000000000..a72597cb050
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_initialAggregate.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_logConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_logConc.xml
new file mode 100644
index 00000000000..0cb9d89de44
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/ChainGenericSerial1D/ChainSerial_logConc.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_advective_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_advective_base.xml
new file mode 100644
index 00000000000..220cbce513c
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_advective_base.xml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_advective_main.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_advective_main.xml
new file mode 100644
index 00000000000..f44b3fde1d0
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_advective_main.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_base.xml
new file mode 100644
index 00000000000..aa3cf8c3932
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_base.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_diffusive_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_diffusive_base.xml
new file mode 100644
index 00000000000..311fa6e9d4a
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_diffusive_base.xml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_diffusive_main.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_diffusive_main.xml
new file mode 100644
index 00000000000..09cdc2ef3f3
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_diffusive_main.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_initialAggregate.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_initialAggregate.xml
new file mode 100644
index 00000000000..d17545e2d17
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_initialAggregate.xml
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_initialPrimaryConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_initialPrimaryConc.xml
new file mode 100644
index 00000000000..0c996c4f429
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_initialPrimaryConc.xml
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_logConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_logConc.xml
new file mode 100644
index 00000000000..b694ac4c669
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy1D/MoMaS_logConc.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_2DAdvective_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_2DAdvective_base.xml
new file mode 100644
index 00000000000..a7f6e107b6d
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_2DAdvective_base.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_2DAdvective_main.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_2DAdvective_main.xml
new file mode 100644
index 00000000000..756a23901ab
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_2DAdvective_main.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_base.xml
new file mode 100644
index 00000000000..7c4059813cc
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_base.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_initialAggregate.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_initialAggregate.xml
new file mode 100644
index 00000000000..d17545e2d17
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_initialAggregate.xml
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_initialPrimaryConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_initialPrimaryConc.xml
new file mode 100644
index 00000000000..0c996c4f429
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_initialPrimaryConc.xml
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_logConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_logConc.xml
new file mode 100644
index 00000000000..b694ac4c669
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkEasy2D/MoMaS_logConc.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_advective_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_advective_base.xml
new file mode 100644
index 00000000000..2e180c91c2c
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_advective_base.xml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_advective_main.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_advective_main.xml
new file mode 100644
index 00000000000..ab2396f9633
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_advective_main.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_base.xml
new file mode 100644
index 00000000000..f1ed51c7534
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_base.xml
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_initialAggregate.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_initialAggregate.xml
new file mode 100644
index 00000000000..2fb76a9a089
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_initialAggregate.xml
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_initialPrimaryConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_initialPrimaryConc.xml
new file mode 100644
index 00000000000..01742f28856
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_initialPrimaryConc.xml
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_logConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_logConc.xml
new file mode 100644
index 00000000000..1b39e7f1cfa
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSBenchmarkMedium1D/MoMaS_logConc.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_base.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_base.xml
new file mode 100644
index 00000000000..d68d6f952a9
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_base.xml
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_initialAggregate.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_initialAggregate.xml
new file mode 100644
index 00000000000..67937e658db
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_initialAggregate.xml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_initialPrimaryConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_initialPrimaryConc.xml
new file mode 100644
index 00000000000..d876342094d
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_initialPrimaryConc.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_logConc.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_logConc.xml
new file mode 100644
index 00000000000..b694ac4c669
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_logConc.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_main.xml b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_main.xml
new file mode 100644
index 00000000000..2700613496e
--- /dev/null
+++ b/inputFiles/singlePhaseFlow/reactiveTransport/MoMaSSmoke/MoMaS_main.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cmake/GeosxOptions.cmake b/src/cmake/GeosxOptions.cmake
index fe3adabcc4b..1e504a6ed90 100644
--- a/src/cmake/GeosxOptions.cmake
+++ b/src/cmake/GeosxOptions.cmake
@@ -36,6 +36,8 @@ endif()
option( ENABLE_PVTPackage "" ON )
+option( ENABLE_HPCREACT "" ON )
+
option( ENABLE_UNCRUSTIFY "" ON )
option( ENABLE_XML_UPDATES "" ON )
diff --git a/src/coreComponents/constitutive/CMakeLists.txt b/src/coreComponents/constitutive/CMakeLists.txt
index c835c57966f..0f3409902f5 100644
--- a/src/coreComponents/constitutive/CMakeLists.txt
+++ b/src/coreComponents/constitutive/CMakeLists.txt
@@ -125,12 +125,8 @@ set( constitutive_headers
fluid/multifluid/compositional/parameters/PressureTemperatureCoordinates.hpp
fluid/multifluid/compositional/CompositionalMultiphaseFluid.hpp
fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.hpp
- fluid/multifluid/reactive/ReactiveBrineFluid.hpp
- fluid/multifluid/reactive/ReactiveMultiFluid.hpp
- fluid/multifluid/reactive/ReactiveMultiFluidFields.hpp
- fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp
- fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp
- fluid/multifluid/reactive/chemicalReactions/ReactionsBase.hpp
+ fluid/reactivefluid/ReactiveFluidFields.hpp
+ fluid/reactivefluid/ReactiveFluidLayouts.hpp
fluid/singlefluid/CompressibleSinglePhaseFluid.hpp
fluid/singlefluid/ParticleFluid.hpp
fluid/singlefluid/ParticleFluidBase.hpp
@@ -191,8 +187,10 @@ set( constitutive_headers
solid/InvariantDecompositions.hpp
solid/PorousDamageSolid.hpp
solid/PerfectlyPlastic.hpp
+ solid/PorousReactiveSolid.hpp
solid/PorousSolid.hpp
solid/PropertyConversions.hpp
+ solid/ReactiveSolid.hpp
solid/SolidBase.hpp
solid/SolidUtilities.hpp
solid/SolidInternalEnergy.hpp
@@ -208,6 +206,7 @@ set( constitutive_headers
solid/porosity/PorosityBase.hpp
solid/porosity/PressurePorosity.hpp
solid/porosity/ProppantPorosity.hpp
+ solid/porosity/ReactivePorosity.hpp
thermalConductivity/MultiPhaseConstantThermalConductivity.hpp
thermalConductivity/MultiPhaseThermalConductivityBase.hpp
thermalConductivity/MultiPhaseThermalConductivityFields.hpp
@@ -282,11 +281,6 @@ set( constitutive_sources
fluid/multifluid/compositional/parameters/PressureTemperatureCoordinates.cpp
fluid/multifluid/compositional/CompositionalMultiphaseFluid.cpp
fluid/multifluid/compositional/CompositionalMultiphaseFluidUpdates.cpp
- fluid/multifluid/reactive/ReactiveBrineFluid.cpp
- fluid/multifluid/reactive/ReactiveMultiFluid.cpp
- fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.cpp
- fluid/multifluid/reactive/chemicalReactions/KineticReactions.cpp
- fluid/multifluid/reactive/chemicalReactions/ReactionsBase.cpp
fluid/singlefluid/CompressibleSinglePhaseFluid.cpp
fluid/singlefluid/ParticleFluid.cpp
fluid/singlefluid/ParticleFluidBase.cpp
@@ -335,7 +329,9 @@ set( constitutive_sources
solid/ElasticOrthotropic.cpp
solid/PorousDamageSolid.cpp
solid/PerfectlyPlastic.cpp
+ solid/PorousReactiveSolid.cpp
solid/PorousSolid.cpp
+ solid/ReactiveSolid.cpp
solid/SolidBase.cpp
solid/SolidInternalEnergy.cpp
solid/CeramicDamage.cpp
@@ -343,6 +339,7 @@ set( constitutive_sources
solid/porosity/PorosityBase.cpp
solid/porosity/PressurePorosity.cpp
solid/porosity/ProppantPorosity.cpp
+ solid/porosity/ReactivePorosity.cpp
thermalConductivity/MultiPhaseConstantThermalConductivity.cpp
thermalConductivity/MultiPhaseThermalConductivityBase.cpp
thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.cpp
@@ -367,6 +364,25 @@ if( ENABLE_PVTPackage )
list( APPEND dependencyList PVTPackage )
endif()
+if (ENABLE_HPCREACT)
+ set( constitutive_headers
+ ${constitutive_headers}
+ fluid/reactivefluid/ReactiveFluidSelector.hpp
+ )
+
+ set( constitutive_headers
+ ${constitutive_headers}
+ fluid/reactivefluid/ReactiveSinglePhaseFluid.hpp
+ )
+
+ set( constitutive_sources
+ ${constitutive_sources}
+ fluid/reactivefluid/ReactiveSinglePhaseFluid.cpp
+ )
+ add_subdirectory( HPCReact )
+ list( APPEND dependencyList hpcReact )
+endif()
+
geos_decorate_link_dependencies( LIST decoratedDependencies
DEPENDENCIES ${dependencyList} )
diff --git a/src/coreComponents/constitutive/ConstitutivePassThru.hpp b/src/coreComponents/constitutive/ConstitutivePassThru.hpp
index 48467e5c1d8..1b8bd91fe79 100644
--- a/src/coreComponents/constitutive/ConstitutivePassThru.hpp
+++ b/src/coreComponents/constitutive/ConstitutivePassThru.hpp
@@ -36,13 +36,16 @@
#include "solid/ElasticIsotropicPressureDependent.hpp"
#include "solid/ElasticTransverseIsotropic.hpp"
#include "solid/ElasticOrthotropic.hpp"
+#include "solid/PorousReactiveSolid.hpp"
#include "solid/PorousSolid.hpp"
#include "solid/PorousDamageSolid.hpp"
#include "solid/CompressibleSolid.hpp"
#include "solid/ProppantSolid.hpp"
#include "solid/CeramicDamage.hpp"
+#include "solid/ReactiveSolid.hpp"
#include "solid/porosity/PressurePorosity.hpp"
#include "solid/porosity/ProppantPorosity.hpp"
+#include "solid/porosity/ReactivePorosity.hpp"
#include "permeability/ConstantPermeability.hpp"
#include "permeability/CarmanKozenyPermeability.hpp"
#include "permeability/ExponentialDecayPermeability.hpp"
@@ -337,6 +340,21 @@ struct ConstitutivePassThru< PorousDamageSolidBase >
}
};
+/**
+ * Specialization for the PorousReactiveSolid models.
+ */
+template<>
+struct ConstitutivePassThru< PorousReactiveSolidBase >
+{
+ template< typename LAMBDA >
+ static void execute( ConstitutiveBase & constitutiveRelation, LAMBDA && lambda )
+ {
+ ConstitutivePassThruHandler< PorousReactiveSolid< ElasticIsotropic, ConstantPermeability >,
+ PorousReactiveSolid< ElasticIsotropic, CarmanKozenyPermeability > >::execute( constitutiveRelation,
+ std::forward< LAMBDA >( lambda ) );
+ }
+};
+
/**
* Specialization for the CompressibleSolid models.
*/
@@ -372,6 +390,34 @@ struct ConstitutivePassThru< CompressibleSolidBase >
}
};
+/**
+ * Specialization for the ReactiveSolid models.
+ */
+template<>
+struct ConstitutivePassThru< ReactiveSolidBase >
+{
+ template< typename LAMBDA >
+ static void execute( ConstitutiveBase & constitutiveRelation, LAMBDA && lambda )
+ {
+ ConstitutivePassThruHandler< ReactiveSolid< ReactivePorosity, ConstantPermeability >,
+ ReactiveSolid< ReactivePorosity, CarmanKozenyPermeability >,
+ ReactiveSolid< ReactivePorosity, PressurePermeability >
+ >::execute( constitutiveRelation,
+ std::forward< LAMBDA >( lambda ) );
+ }
+
+ template< typename LAMBDA >
+ static void execute( ConstitutiveBase const & constitutiveRelation, LAMBDA && lambda )
+ {
+ ConstitutivePassThruHandler< ReactiveSolid< ReactivePorosity, ConstantPermeability >,
+ ReactiveSolid< ReactivePorosity, CarmanKozenyPermeability >,
+ ReactiveSolid< ReactivePorosity, PressurePermeability >
+ >::execute( constitutiveRelation,
+ std::forward< LAMBDA >( lambda ) );
+ }
+};
+
+
/**
* Specialization for the ProppantModel.
*/
@@ -412,6 +458,8 @@ struct ConstitutivePassThru< CoupledSolidBase >
CompressibleSolid< PressurePorosity, PressurePermeability >,
CompressibleSolid< PressurePorosity, SlipDependentPermeability >,
CompressibleSolid< PressurePorosity, WillisRichardsPermeability >,
+ PorousReactiveSolid< ElasticIsotropic, ConstantPermeability >,
+ PorousReactiveSolid< ElasticIsotropic, CarmanKozenyPermeability >,
PorousSolid< DruckerPragerExtended, ConstantPermeability >,
PorousSolid< ModifiedCamClay, ConstantPermeability >,
PorousSolid< DelftEgg, ConstantPermeability >,
@@ -436,8 +484,11 @@ struct ConstitutivePassThru< CoupledSolidBase >
PorousSolid< ElasticOrthotropic, CarmanKozenyPermeability >,
PorousDamageSolid< DamageSpectral< ElasticIsotropic > >,
PorousDamageSolid< DamageVolDev< ElasticIsotropic > >,
- PorousDamageSolid< Damage< ElasticIsotropic > > >::execute( constitutiveRelation,
- std::forward< LAMBDA >( lambda ) );
+ PorousDamageSolid< Damage< ElasticIsotropic > >,
+ ReactiveSolid< ReactivePorosity, ConstantPermeability >,
+ ReactiveSolid< ReactivePorosity, CarmanKozenyPermeability >,
+ ReactiveSolid< ReactivePorosity, PressurePermeability > >::execute( constitutiveRelation,
+ std::forward< LAMBDA >( lambda ) );
}
template< typename LAMBDA >
@@ -450,6 +501,8 @@ struct ConstitutivePassThru< CoupledSolidBase >
CompressibleSolid< PressurePorosity, PressurePermeability >,
CompressibleSolid< PressurePorosity, SlipDependentPermeability >,
CompressibleSolid< PressurePorosity, WillisRichardsPermeability >,
+ PorousReactiveSolid< ElasticIsotropic, ConstantPermeability >,
+ PorousReactiveSolid< ElasticIsotropic, CarmanKozenyPermeability >,
PorousSolid< DruckerPragerExtended, ConstantPermeability >,
PorousSolid< ModifiedCamClay, ConstantPermeability >,
PorousSolid< DelftEgg, ConstantPermeability >,
@@ -474,8 +527,11 @@ struct ConstitutivePassThru< CoupledSolidBase >
PorousSolid< ElasticOrthotropic, CarmanKozenyPermeability >,
PorousDamageSolid< DamageSpectral< ElasticIsotropic > >,
PorousDamageSolid< DamageVolDev< ElasticIsotropic > >,
- PorousDamageSolid< Damage< ElasticIsotropic > > >::execute( constitutiveRelation,
- std::forward< LAMBDA >( lambda ) );
+ PorousDamageSolid< Damage< ElasticIsotropic > >,
+ ReactiveSolid< ReactivePorosity, ConstantPermeability >,
+ ReactiveSolid< ReactivePorosity, CarmanKozenyPermeability >,
+ ReactiveSolid< ReactivePorosity, PressurePermeability > >::execute( constitutiveRelation,
+ std::forward< LAMBDA >( lambda ) );
}
};
diff --git a/src/coreComponents/constitutive/HPCReact b/src/coreComponents/constitutive/HPCReact
new file mode 160000
index 00000000000..d8dd4b7de58
--- /dev/null
+++ b/src/coreComponents/constitutive/HPCReact
@@ -0,0 +1 @@
+Subproject commit d8dd4b7de58cdf9f37f63042fab18ea4777991fb
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.hpp
deleted file mode 100644
index f1d88712b00..00000000000
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.hpp
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * ------------------------------------------------------------------------------------------------------------
- * 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 ReactiveBrineFluid.hpp
- */
-
-#ifndef GEOS_CONSTITUTIVE_FLUID_REACTIVEBRINEFLUID_HPP_
-#define GEOS_CONSTITUTIVE_FLUID_REACTIVEBRINEFLUID_HPP_
-
-#include "common/format/EnumStrings.hpp"
-#include "constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.hpp"
-#include "constitutive/fluid/multifluid/MultiFluidUtils.hpp"
-#include "constitutive/fluid/multifluid/CO2Brine/PhaseModel.hpp"
-#include "constitutive/fluid/multifluid/CO2Brine/functions/BrineEnthalpy.hpp"
-#include "constitutive/fluid/multifluid/CO2Brine/functions/NoOpPVTFunction.hpp"
-#include "constitutive/fluid/multifluid/CO2Brine/functions/WaterDensity.hpp"
-#include "constitutive/fluid/multifluid/CO2Brine/functions/PhillipsBrineViscosity.hpp"
-#include "constitutive/fluid/multifluid/CO2Brine/functions/PureWaterProperties.hpp"
-#include "common/Units.hpp"
-
-
-
-#include
-
-namespace geos
-{
-
-namespace constitutive
-{
-
-template< typename PHASE >
-class ReactiveBrineFluid : public ReactiveMultiFluid
-{
-public:
-
- using exec_policy = parallelDevicePolicy<>;
-
- ReactiveBrineFluid( string const & name,
- Group * const parent );
-
- virtual std::unique_ptr< ConstitutiveBase >
- deliverClone( string const & name,
- Group * const parent ) const override;
-
- static string catalogName();
-
- virtual string getCatalogName() const override { return catalogName(); }
-
- virtual bool isThermal() const override final;
-
- /**
- * @copydoc MultiFluidBase::checkTablesParameters( real64 pressure, real64 temperature )
- */
- void checkTablesParameters( real64 pressure, real64 temperature ) const override final;
-
- /**
- * @brief Kernel wrapper class for ReactiveBrineFluid.
- */
- class KernelWrapper final : public ReactiveMultiFluid::KernelWrapper
- {
-public:
- GEOS_HOST_DEVICE
- virtual void compute( real64 const pressure,
- real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & composition,
- PhaseProp::SliceType const phaseFraction,
- PhaseProp::SliceType const phaseDensity,
- PhaseProp::SliceType const phaseMassDensity,
- PhaseProp::SliceType const phaseViscosity,
- PhaseProp::SliceType const phaseEnthalpy,
- PhaseProp::SliceType const phaseInternalEnergy,
- PhaseComp::SliceType const phaseCompFraction,
- FluidProp::SliceType const totalDensity ) const override;
-
- GEOS_HOST_DEVICE
- virtual void update( localIndex const k,
- localIndex const q,
- real64 const pressure,
- real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & composition ) const override;
-
- virtual void updateChemistry( localIndex const k,
- localIndex const q,
- real64 const pressure,
- real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & composition ) const override;
-
-private:
-
- friend class ReactiveBrineFluid;
-
- KernelWrapper( PHASE const & phase,
- arrayView1d< real64 const > componentMolarWeight,
- bool const useMass,
- bool const isThermal,
- PhaseProp::ViewType phaseFraction,
- PhaseProp::ViewType phaseDensity,
- PhaseProp::ViewType phaseMassDensity,
- PhaseProp::ViewType phaseViscosity,
- PhaseProp::ViewType phaseEnthalpy,
- PhaseProp::ViewType phaseInternalEnergy,
- PhaseComp::ViewType phaseCompFraction,
- FluidProp::ViewType totalDensity,
- integer const numPrimarySpecies,
- chemicalReactions::EquilibriumReactions const & equilibriumReactions,
- chemicalReactions::KineticReactions const & kineticReactions,
- arrayView2d< real64, compflow::USD_COMP > const & primarySpeciesConcentration,
- arrayView2d< real64, compflow::USD_COMP > const & secondarySpeciesConcentration,
- arrayView2d< real64, compflow::USD_COMP > const & primarySpeciesTotalConcentration,
- arrayView2d< real64, compflow::USD_COMP > const & kineticReactionRates );
-
-
- /// Flag to specify whether the model is thermal or not
- bool m_isThermal;
-
- /// Brine constitutive kernel wrappers
- typename PHASE::KernelWrapper m_phase;
-
- };
-
- virtual integer getWaterPhaseIndex() const override final;
-
- /**
- * @brief Names of the submodels for input
- */
- enum class SubModelInputNames : integer
- {
- DENSITY, ///< the keyword for the density model
- VISCOSITY, ///< the keyword for the viscosity model
- ENTHALPY ///< the keyword for the enthalpy model
- };
-
- /**
- * @brief Create an update kernel wrapper.
- * @return the wrapper
- */
- KernelWrapper createKernelWrapper();
-
- struct viewKeyStruct : ReactiveMultiFluid::viewKeyStruct
- {
- static constexpr char const * phasePVTParaFilesString() { return "phasePVTParaFiles"; }
- static constexpr char const * writeCSVFlagString() { return "writeCSV"; }
- };
-
-protected:
-
- virtual void postInputInitialization() override;
-
-private:
-
- /**
- * @brief Create a PVT Model and output them
- */
- void createPVTModels();
-
- /// Names of the files defining the viscosity and density models
- path_array m_phasePVTParaFiles;
-
- /// Output csv file containing informations about PVT
- integer m_writeCSV;
-
- /// Brine constitutive models
- std::unique_ptr< PHASE > m_phase;
-
-};
-
-// these aliases are useful in constitutive dispatch
-using ReactiveBrine =
- ReactiveBrineFluid< PhaseModel< PVTProps::WaterDensity, PVTProps::PhillipsBrineViscosity, PVTProps::NoOpPVTFunction > >;
-using ReactiveBrineThermal =
- ReactiveBrineFluid< PhaseModel< PVTProps::WaterDensity, PVTProps::PhillipsBrineViscosity, PVTProps::BrineEnthalpy > >;
-
-template< typename PHASE >
-GEOS_HOST_DEVICE
-inline void
-ReactiveBrineFluid< PHASE >::KernelWrapper::
- compute( real64 const pressure,
- real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & composition,
- PhaseProp::SliceType const phaseFraction,
- PhaseProp::SliceType const phaseDensity,
- PhaseProp::SliceType const phaseMassDensity,
- PhaseProp::SliceType const phaseViscosity,
- PhaseProp::SliceType const phaseEnthalpy,
- PhaseProp::SliceType const phaseInternalEnergy,
- PhaseComp::SliceType const phaseCompFraction,
- FluidProp::SliceType const totalDensity ) const
-{
- integer constexpr numComp = chemicalReactions::ReactionsBase::maxNumPrimarySpecies;
-
- // 1. We perform a sort of single phase flash
- stackArray1d< real64, numComp > compMoleFrac( composition.size() );
-
- phaseFraction.value[0] = 1.0; // it's a single phase system
- for( integer ic = 0; ic < composition.size(); ++ic )
- {
- compMoleFrac[ic] = composition[ic];
- phaseCompFraction.value[0][ic] = composition[ic];
- }
-
- real64 const temperatureInCelsius = units::convertKToC( temperature );
-
- // 2. Compute phase densities and phase viscosities
- m_phase.density.compute( pressure,
- temperatureInCelsius,
- phaseCompFraction.value[0].toSliceConst(), phaseCompFraction.derivs[0].toSliceConst(),
- phaseDensity.value[0], phaseDensity.derivs[0],
- m_useMass );
-
- m_phase.viscosity.compute( pressure,
- temperatureInCelsius,
- phaseCompFraction.value[0].toSliceConst(), phaseCompFraction.derivs[0].toSliceConst(),
- phaseViscosity.value[0], phaseViscosity.derivs[0],
- m_useMass );
-
-
- // for now, we have to compute the phase mass density here
- m_phase.density.compute( pressure,
- temperatureInCelsius,
- phaseCompFraction.value[0].toSliceConst(), phaseCompFraction.derivs[0].toSliceConst(),
- phaseMassDensity.value[0], phaseMassDensity.derivs[0],
- true );
-
- // 3. Compute enthalpy and internal energy
- if( m_isThermal )
- {
- m_phase.enthalpy.compute( pressure,
- temperatureInCelsius,
- phaseCompFraction.value[0].toSliceConst(), phaseCompFraction.derivs[0].toSliceConst(),
- phaseEnthalpy.value[0], phaseEnthalpy.derivs[0],
- m_useMass );
-
- computeInternalEnergy( pressure,
- phaseFraction,
- phaseMassDensity,
- phaseEnthalpy,
- phaseInternalEnergy );
- }
-
- // 6. Compute total fluid mass/molar density and derivatives
- computeTotalDensity( phaseFraction,
- phaseDensity,
- totalDensity );
-}
-
-template< typename PHASE >
-GEOS_HOST_DEVICE inline void
-ReactiveBrineFluid< PHASE >::KernelWrapper::
- update( localIndex const k,
- localIndex const q,
- real64 const pressure,
- real64 const temperature,
- arraySlice1d< geos::real64 const, compflow::USD_COMP - 1 > const & composition ) const
-{
- compute( pressure,
- temperature,
- composition,
- m_phaseFraction( k, q ),
- m_phaseDensity( k, q ),
- m_phaseMassDensity( k, q ),
- m_phaseViscosity( k, q ),
- m_phaseEnthalpy( k, q ),
- m_phaseInternalEnergy( k, q ),
- m_phaseCompFraction( k, q ),
- m_totalDensity( k, q ) );
-}
-
-template< typename PHASE >
-inline void
-ReactiveBrineFluid< PHASE >::KernelWrapper::
- updateChemistry( localIndex const k,
- localIndex const q,
- real64 const pressure,
- real64 const temperature,
- arraySlice1d< geos::real64 const, compflow::USD_COMP - 1 > const & composition ) const
-
-{
- real64 const totalMolecularWeight = PVTProps::PureWaterProperties::MOLECULAR_WEIGHT;
-
- convertMoleFractionToMolarity( m_totalDensity( k, q ).value,
- totalMolecularWeight,
- composition,
- m_primarySpeciesTotalConcentration[k] );
-
- computeChemistry( pressure,
- temperature,
- m_primarySpeciesTotalConcentration[k],
- m_primarySpeciesConcentration[k],
- m_secondarySpeciesConcentration[k],
- m_kineticReactionRates[k] );
-}
-
-
-} // namespace constitutive
-
-} // namespace geos
-
-#endif //GEOS_CONSTITUTIVE_FLUID_REACTIVEBRINEFLUID_HPP_
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.cpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.cpp
deleted file mode 100644
index 3f59b5ac30b..00000000000
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * ------------------------------------------------------------------------------------------------------------
- * 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 ReactiveMultiFluid.cpp
- */
-#include "ReactiveMultiFluid.hpp"
-#include "ReactiveMultiFluidFields.hpp"
-
-
-namespace geos
-{
-
-using namespace dataRepository;
-
-namespace constitutive
-{
-
-ReactiveMultiFluid::
- ReactiveMultiFluid( string const & name, Group * const parent ):
- MultiFluidBase( name, parent )
-{
- // For now this is being hardcoded. We will see where this should come from.
- m_numPrimarySpecies = 7;
- m_numSecondarySpecies = 11;
- m_numKineticReactions = 2;
-
- registerField< fields::reactivefluid::primarySpeciesConcentration >( &m_primarySpeciesConcentration );
- registerField< fields::reactivefluid::secondarySpeciesConcentration >( &m_secondarySpeciesConcentration );
- registerField< fields::reactivefluid::primarySpeciesTotalConcentration >( &m_primarySpeciesTotalConcentration );
- registerField< fields::reactivefluid::kineticReactionRates >( &m_kineticReactionRates );
-}
-
-bool ReactiveMultiFluid::isThermal() const
-{
- return true;
-}
-
-std::unique_ptr< ConstitutiveBase > ReactiveMultiFluid::
- deliverClone( string const & name, Group * const parent ) const
-{
- std::unique_ptr< ConstitutiveBase > clone = MultiFluidBase::deliverClone( name, parent );
-
- ReactiveMultiFluid & newConstitutiveRelation = dynamicCast< ReactiveMultiFluid & >( *clone );
-
- newConstitutiveRelation.createChemicalReactions();
-
- return clone;
-}
-
-void ReactiveMultiFluid::postInputInitialization()
-{
- MultiFluidBase::postInputInitialization();
-
- GEOS_THROW_IF_NE_MSG( numFluidPhases(), 1,
- GEOS_FMT( "{}: invalid number of phases", getFullName() ),
- InputError );
-
- createChemicalReactions();
-}
-
-void ReactiveMultiFluid::allocateConstitutiveData( Group & parent,
- localIndex const numPts )
-{
- integer const numPrimarySpecies = this->numPrimarySpecies();
- integer const numSecondarySpecies = this->numSecondarySpecies();
- integer const numKineticReactions = this->numKineticReactions();
-
- m_primarySpeciesConcentration.resize( 0, numPrimarySpecies );
- m_secondarySpeciesConcentration.resize( 0, numSecondarySpecies );
- m_primarySpeciesTotalConcentration.resize( 0, numPrimarySpecies );
- m_kineticReactionRates.resize( 0, numKineticReactions );
-
- MultiFluidBase::allocateConstitutiveData( parent, numPts );
-}
-
-void ReactiveMultiFluid::createChemicalReactions()
-{
- // instantiate reactions objects
- m_equilibriumReactions = std::make_unique< chemicalReactions::EquilibriumReactions >( getName() + "_equilibriumReactions", m_numPrimarySpecies, m_numSecondarySpecies );
- m_kineticReactions = std::make_unique< chemicalReactions::KineticReactions >( getName() + "_kineticReactions", m_numPrimarySpecies, m_numSecondarySpecies, m_numKineticReactions );
-}
-
-} //namespace constitutive
-
-} //namespace geos
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.hpp
deleted file mode 100644
index c4e2719aeed..00000000000
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluid.hpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * ------------------------------------------------------------------------------------------------------------
- * 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 ReactiveMultiFluid.hpp
- */
-
-#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_REACTIVEMULTIFLUID_HPP_
-#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_REACTIVEMULTIFLUID_HPP_
-
-
-#include "common/format/EnumStrings.hpp"
-#include "constitutive/fluid/multifluid/MultiFluidBase.hpp"
-#include "constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp"
-#include "constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp"
-
-#include
-
-namespace geos
-{
-
-namespace constitutive
-{
-
-class ReactiveMultiFluid : public MultiFluidBase
-{
-public:
-
- using exec_policy = serialPolicy;
-
- ReactiveMultiFluid( string const & name,
- dataRepository::Group * const parent );
-
- virtual std::unique_ptr< ConstitutiveBase >
- deliverClone( string const & name,
- dataRepository::Group * const parent ) const override;
-
- virtual void allocateConstitutiveData( dataRepository::Group & parent,
- localIndex const numPts ) override;
-
- virtual bool isThermal() const override;
-
- arrayView2d< real64 const, compflow::USD_COMP > primarySpeciesConcentration() const
- { return m_primarySpeciesConcentration; }
-
- arrayView2d< real64 const, compflow::USD_COMP > secondarySpeciesConcentration() const
- { return m_secondarySpeciesConcentration; }
-
- arrayView2d< real64 const, compflow::USD_COMP > kineticReactionRates() const
- { return m_kineticReactionRates; }
-
- integer numPrimarySpecies() const { return m_numPrimarySpecies; }
-
- integer numSecondarySpecies() const { return m_numSecondarySpecies; }
-
- integer numKineticReactions() const { return m_numKineticReactions; }
-
- /**
- * @brief Kernel wrapper class for ReactiveMultiFluid.
- */
- class KernelWrapper : public MultiFluidBase::KernelWrapper
- {
-
-public:
-
- void computeChemistry( real64 const pressure,
- real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesTotalConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & kineticReactionRates ) const;
-
- virtual void updateChemistry( localIndex const k,
- localIndex const q,
- real64 const pressure,
- real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & composition ) const = 0;
-
- /**
- * @brief Construct a new Kernel Wrapper object
- *
- * @param componentMolarWeight
- * @param useMass
- * @param isThermal
- * @param phaseFraction
- * @param phaseDensity
- * @param phaseMassDensity
- * @param phaseViscosity
- * @param phaseEnthalpy
- * @param phaseInternalEnergy
- * @param phaseCompFraction
- * @param totalDensity
- * @param numPrimarySpecies
- * @param equilibriumReactions
- * @param kineticReactions
- * @param primarySpeciesConcentration
- * @param secondarySpeciesConcentration
- * @param primarySpeciesTotalConcentration
- * @param kineticReactionRates
- */
- KernelWrapper( arrayView1d< real64 const > componentMolarWeight,
- bool const useMass,
- PhaseProp::ViewType phaseFraction,
- PhaseProp::ViewType phaseDensity,
- PhaseProp::ViewType phaseMassDensity,
- PhaseProp::ViewType phaseViscosity,
- PhaseProp::ViewType phaseEnthalpy,
- PhaseProp::ViewType phaseInternalEnergy,
- PhaseComp::ViewType phaseCompFraction,
- FluidProp::ViewType totalDensity,
- integer const numPrimarySpecies,
- chemicalReactions::EquilibriumReactions const & equilibriumReactions,
- chemicalReactions::KineticReactions const & kineticReactions,
- arrayView2d< real64, compflow::USD_COMP > const & primarySpeciesConcentration,
- arrayView2d< real64, compflow::USD_COMP > const & secondarySpeciesConcentration,
- arrayView2d< real64, compflow::USD_COMP > const & primarySpeciesTotalConcentration,
- arrayView2d< real64, compflow::USD_COMP > const & kineticReactionRates ):
- MultiFluidBase::KernelWrapper( std::move( componentMolarWeight ),
- useMass,
- std::move( phaseFraction ),
- std::move( phaseDensity ),
- std::move( phaseMassDensity ),
- std::move( phaseViscosity ),
- std::move( phaseEnthalpy ),
- std::move( phaseInternalEnergy ),
- std::move( phaseCompFraction ),
- std::move( totalDensity ) ),
- m_numPrimarySpecies( numPrimarySpecies ),
- m_equilibriumReactions( equilibriumReactions.createKernelWrapper() ),
- m_kineticReactions( kineticReactions.createKernelWrapper() ),
- m_primarySpeciesConcentration( primarySpeciesConcentration ),
- m_secondarySpeciesConcentration( secondarySpeciesConcentration ),
- m_primarySpeciesTotalConcentration( primarySpeciesTotalConcentration ),
- m_kineticReactionRates( kineticReactionRates )
- {}
-
-protected:
-
- void convertMoleFractionToMolarity( real64 const totalDensity,
- real64 const totalMolecularWeight,
- arraySlice1d< geos::real64 const, compflow::USD_COMP - 1 > const & composition,
- arraySlice1d< geos::real64, compflow::USD_COMP - 1 > const & primarySpeciesTotalConcentration ) const;
-
- friend class ReactiveMultiFluid;
- /// Reaction related terms
- integer m_numPrimarySpecies;
-
- chemicalReactions::EquilibriumReactions::KernelWrapper m_equilibriumReactions;
-
- chemicalReactions::KineticReactions::KernelWrapper m_kineticReactions;
-
- arrayView2d< real64, compflow::USD_COMP > m_primarySpeciesConcentration;
-
- arrayView2d< real64, compflow::USD_COMP > m_secondarySpeciesConcentration;
-
- arrayView2d< real64, compflow::USD_COMP > m_primarySpeciesTotalConcentration;
-
- arrayView2d< real64, compflow::USD_COMP > m_kineticReactionRates;
- };
-
- struct viewKeyStruct : ConstitutiveBase::viewKeyStruct
- {};
-
-protected:
-
- virtual void postInputInitialization() override;
-
- void createChemicalReactions();
-
- /// Reaction related terms
- integer m_numPrimarySpecies;
-
- integer m_numSecondarySpecies;
-
- integer m_numKineticReactions;
-
- std::unique_ptr< chemicalReactions::EquilibriumReactions > m_equilibriumReactions;
-
- std::unique_ptr< chemicalReactions::KineticReactions > m_kineticReactions;
-
- array2d< real64, constitutive::multifluid::LAYOUT_FLUID > m_primarySpeciesConcentration;
-
- array2d< real64, constitutive::multifluid::LAYOUT_FLUID > m_secondarySpeciesConcentration;
-
- array2d< real64, constitutive::multifluid::LAYOUT_FLUID > m_primarySpeciesTotalConcentration;
-
- array2d< real64, constitutive::multifluid::LAYOUT_FLUID > m_kineticReactionRates;
-};
-
-inline void
-ReactiveMultiFluid::KernelWrapper::
- computeChemistry( real64 const pressure,
- real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesTotalConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & kineticReactionRates ) const
-{
- GEOS_UNUSED_VAR( pressure );
-
- // 2. solve for equilibrium
- m_equilibriumReactions.updateConcentrations( temperature,
- primarySpeciesTotalConcentration,
- primarySpeciesConcentration,
- secondarySpeciesConcentration );
-
- // 3. compute kinetic reaction rates
- m_kineticReactions.computeReactionRates( temperature,
- primarySpeciesConcentration,
- secondarySpeciesConcentration,
- kineticReactionRates );
-}
-
-
-inline void
-ReactiveMultiFluid::KernelWrapper::
- convertMoleFractionToMolarity( real64 const totalDensity,
- real64 const totalMolecularWeight,
- arraySlice1d< geos::real64 const, compflow::USD_COMP - 1 > const & composition,
- arraySlice1d< geos::real64, compflow::USD_COMP - 1 > const & primarySpeciesTotalConcentration ) const
-{
- // 1. Convert from mole fraction to molarity ( mol/L )
- real64 const conversionFactor = totalDensity / totalMolecularWeight * 1e-3; //conversion to L instead of cubic meters
- for( int i=0; i < m_numPrimarySpecies; i++ )
- {
- primarySpeciesTotalConcentration[i] = composition[i] * conversionFactor;
- }
-}
-
-} // namespace constitutive
-
-} // namespace geos
-
-#endif //GEOS_CONSTITUTIVE_FLUID_REACTIVEMULTIFLUID_HPP
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluidFields.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluidFields.hpp
deleted file mode 100644
index d3a3a77f967..00000000000
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveMultiFluidFields.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * ------------------------------------------------------------------------------------------------------------
- * 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 ReactiveMultiFluidFields.hpp
- */
-
-#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_MULTIFLUIDFIELDS_HPP_
-#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_MULTIFLUIDFIELDS_HPP_
-
-#include "constitutive/fluid/multifluid/Layouts.hpp"
-#include "mesh/MeshFields.hpp"
-
-namespace geos
-{
-
-namespace fields
-{
-
-namespace reactivefluid
-{
-
-using array2dLayoutComp = array2d< real64, compflow::LAYOUT_COMP >;
-
-DECLARE_FIELD( primarySpeciesConcentration,
- "primarySpeciesConcentration",
- array2dLayoutComp,
- 0,
- LEVEL_0,
- WRITE_AND_READ,
- "primarySpeciesConcentration" );
-
-DECLARE_FIELD( primarySpeciesTotalConcentration,
- "primarySpeciesTotalConcentration",
- array2dLayoutComp,
- 0,
- LEVEL_0,
- WRITE_AND_READ,
- "primarySpeciesTotalConcentration" );
-
-DECLARE_FIELD( secondarySpeciesConcentration,
- "secondarySpeciesConcentration",
- array2dLayoutComp,
- 0,
- LEVEL_0,
- WRITE_AND_READ,
- "secondarySpeciesConcentration" );
-
-DECLARE_FIELD( kineticReactionRates,
- "kineticReactionRates",
- array2dLayoutComp,
- 0,
- LEVEL_0,
- WRITE_AND_READ,
- "kineticReactionRates" );
-}
-
-}
-
-}
-
-#endif // GEOS_CONSTITUTIVE_FLUID_MULTIFLUIDFIELDS_HPP_
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.cpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.cpp
deleted file mode 100644
index 8ae3e0c8ee2..00000000000
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * ------------------------------------------------------------------------------------------------------------
- * 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 EquilibriumReactions.cpp
- */
-
-#include "EquilibriumReactions.hpp"
-
-#include "functions/FunctionManager.hpp"
-#include "denseLinearAlgebra/interfaces/blaslapack/BlasLapackLA.hpp"
-
-namespace geos
-{
-
-using namespace stringutilities;
-
-namespace constitutive
-{
-
-namespace chemicalReactions
-{
-
-EquilibriumReactions::EquilibriumReactions( string const & name, integer const numPrimarySpecies, integer const numSecSpecies ):
- ReactionsBase( name, numPrimarySpecies, numSecSpecies )
-{
- // Here we should either read the database or the input values.
-
- // Hardcoding values for now
-
-
-
- // Stochiometric Matrix
- // First index: 0 = OH-, 1 = CO2, 2 = CO3-2, 3 = H2CO3, 4 = CaHCO3+, 5 = CaCO3, 6 = CaSO4, 7 = CaCl+, 8 = CaCl2, 9 = MgSO4, 10 = NaSO4-
- // Second index: 0 = H+, 1 = HCO3-, 2 = Ca+2, 3 = SO4-2, 4 = Cl-, 5 = Mg+2, 6 = Na+1
- m_stoichMatrix.resize( m_numSecondarySpecies, m_numPrimarySpecies );
- m_stoichMatrix[0][0] = -1;
- m_stoichMatrix[1][0] = 1;
- m_stoichMatrix[1][1] = 1;
- m_stoichMatrix[2][0] = -1;
- m_stoichMatrix[2][1] = 1;
- m_stoichMatrix[3][0] = 1;
- m_stoichMatrix[3][1] = 1;
- m_stoichMatrix[4][1] = 1;
- m_stoichMatrix[4][2] = 1;
- m_stoichMatrix[5][0] = -1;
- m_stoichMatrix[5][1] = 1;
- m_stoichMatrix[5][2] = 1;
- m_stoichMatrix[6][2] = 1;
- m_stoichMatrix[6][3] = 1;
- m_stoichMatrix[7][2] = 1;
- m_stoichMatrix[7][4] = 1;
- m_stoichMatrix[8][2] = 1;
- m_stoichMatrix[8][4] = 2;
- m_stoichMatrix[9][5] = 1;
- m_stoichMatrix[9][3] = 1;
- m_stoichMatrix[10][6] = 1;
- m_stoichMatrix[10][3] = 1;
-
- // Equilibrium Constant
- m_log10EqConst.resize( m_numSecondarySpecies );
- m_log10EqConst[0] = 13.99;
- m_log10EqConst[1] = -6.36;
- m_log10EqConst[2] = 10.33;
- m_log10EqConst[3] = -3.77;
- m_log10EqConst[4] = -1.09;
- m_log10EqConst[5] = 7.07;
- m_log10EqConst[6] = -2.16;
- m_log10EqConst[7] = 0.67;
- m_log10EqConst[8] = 0.60;
- m_log10EqConst[9] = -2.43;
- m_log10EqConst[10] = -0.82;
-}
-
-EquilibriumReactions::KernelWrapper EquilibriumReactions::createKernelWrapper() const
-{
- return KernelWrapper( m_numPrimarySpecies,
- m_numSecondarySpecies,
- m_log10EqConst,
- m_stoichMatrix,
- m_chargePrimary,
- m_chargeSec,
- m_ionSizePrimary,
- m_ionSizeSec,
- m_DebyeHuckelA,
- m_DebyeHuckelB,
- m_WATEQBDot );
-}
-
-void EquilibriumReactions::KernelWrapper::assembleEquilibriumReactionSystem( real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesTotalConcentration,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration,
- arraySlice2d< real64 > const & matrix,
- arraySlice1d< real64 > const & rhs ) const
-{
-
- stackArray1d< real64, ReactionsBase::maxNumPrimarySpecies > log10PrimaryActCoeff( m_numPrimarySpecies );
- stackArray1d< real64, ReactionsBase::maxNumSecondarySpecies > log10SecActCoeff( m_numSecondarySpecies );
- stackArray2d< real64, ReactionsBase::maxNumSecondarySpecies * ReactionsBase::maxNumPrimarySpecies > dLog10SecConc_dLog10PrimaryConc( m_numSecondarySpecies, m_numPrimarySpecies );
- stackArray1d< real64, ReactionsBase::maxNumPrimarySpecies > totalConcentration( m_numPrimarySpecies );
- stackArray2d< real64, ReactionsBase::maxNumPrimarySpecies * ReactionsBase::maxNumPrimarySpecies > dTotalConc_dLog10PrimaryConc( m_numPrimarySpecies, m_numPrimarySpecies );
-
- real64 ionicStrength = 0.0;
- stackArray1d< real64, ReactionsBase::maxNumPrimarySpecies > dIonicStrength_dPrimaryConcentration( m_numPrimarySpecies );
- stackArray1d< real64, ReactionsBase::maxNumPrimarySpecies > dLog10PrimaryActCoeff_dIonicStrength( m_numPrimarySpecies );
- stackArray1d< real64, ReactionsBase::maxNumSecondarySpecies > dLog10SecActCoeff_dIonicStrength( m_numSecondarySpecies );
-
- /// activity coefficients
- computeIonicStrength( primarySpeciesConcentration,
- secondarySpeciesConcentration,
- ionicStrength );
-
- computeLog10ActCoefBDotModel( temperature,
- ionicStrength,
- log10PrimaryActCoeff,
- dLog10PrimaryActCoeff_dIonicStrength,
- log10SecActCoeff,
- dLog10SecActCoeff_dIonicStrength );
-
- computeSeondarySpeciesConcAndDerivative( temperature,
- log10PrimaryActCoeff,
- dLog10PrimaryActCoeff_dIonicStrength,
- log10SecActCoeff,
- dLog10SecActCoeff_dIonicStrength,
- primarySpeciesConcentration,
- secondarySpeciesConcentration,
- dLog10SecConc_dLog10PrimaryConc );
-
- computeTotalConcAndDerivative( temperature,
- primarySpeciesConcentration,
- secondarySpeciesConcentration,
- dLog10SecConc_dLog10PrimaryConc,
- totalConcentration,
- dTotalConc_dLog10PrimaryConc );
-
- for( int i=0; i const & primarySpeciesTotalConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration ) const
-
-{
- stackArray2d< real64, ReactionsBase::maxNumPrimarySpecies * ReactionsBase::maxNumPrimarySpecies > matrix( m_numPrimarySpecies, m_numPrimarySpecies );
- stackArray1d< real64, ReactionsBase::maxNumPrimarySpecies > rhs( m_numPrimarySpecies );
- stackArray1d< real64, ReactionsBase::maxNumPrimarySpecies > solution( m_numPrimarySpecies );
-
- setInitialGuess( primarySpeciesTotalConcentration, primarySpeciesConcentration );
-
- bool converged = false;
- for( int iteration = 0; iteration < m_maxNumIterations; iteration++ )
- {
-
- for( int i = 0; i< m_numPrimarySpecies; i++ )
- {
- rhs[i] = 0.0;
- solution[i] = 0.0;
- for( int j = 0; j< m_numPrimarySpecies; j++ )
- {
- matrix( i, j ) = 0.0;
- }
- }
-
- assembleEquilibriumReactionSystem( temperature,
- primarySpeciesTotalConcentration,
- primarySpeciesConcentration,
- secondarySpeciesConcentration,
- matrix,
- rhs );
-
- real64 const residualNorm = BlasLapackLA::vectorNorm2( rhs.toSliceConst() );
-
- if( residualNorm < m_newtonTol && iteration >= 1 )
- {
- converged = true;
- break;
- }
-
- BlasLapackLA::solveLinearSystem( matrix, rhs, solution );
-
- updatePrimarySpeciesConcentrations( solution, primarySpeciesConcentration );
- }
- GEOS_ERROR_IF( !converged, "Equilibrium reactions did not converge." );
-}
-
-// function to compute the derivative of the concentration of secondary species with respect to the concentration of the primary species.
-void EquilibriumReactions::KernelWrapper::computeSeondarySpeciesConcAndDerivative( real64 const temperature,
- arraySlice1d< real64 const > const & log10PrimaryActCoeff,
- arraySlice1d< real64 const > const & dLog10PrimaryActCoeff_dIonicStrength,
- arraySlice1d< real64 const > const & log10SecActCoeff,
- arraySlice1d< real64 const > const & dLog10SecActCoeff_dIonicStrength,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & secondarySpeciesConectration,
- arraySlice2d< real64 > const & dLog10SecConc_dLog10PrimaryConc ) const
-{
- GEOS_UNUSED_VAR( temperature );
-
- // Compute d(concentration of dependent species)/d(concentration of basis species)
- for( int iSec = 0; iSec < m_numSecondarySpecies; iSec++ )
- {
- real64 log10SecConc = -m_log10EqConst[iSec] - log10SecActCoeff[iSec];
-
- for( int jPri = 0; jPri < m_numPrimarySpecies; jPri++ )
- {
- real64 const dIonicStrength_dPrimaryConc = log( 10 ) * 0.5 * m_chargePrimary[jPri] * m_chargePrimary[jPri];
-
- log10SecConc += m_stoichMatrix[iSec][jPri] * ( log10( primarySpeciesConcentration[jPri] ) + log10PrimaryActCoeff[jPri] );
- dLog10SecConc_dLog10PrimaryConc[iSec][jPri] += m_stoichMatrix[iSec][jPri] - dLog10SecActCoeff_dIonicStrength[iSec] * primarySpeciesConcentration[jPri] *
- dIonicStrength_dPrimaryConc;
- for( int kDerivative = 0; kDerivative < m_numPrimarySpecies; kDerivative++ )
- {
- // add contribution to the derivtive from all primary activity coefficients
- dLog10SecConc_dLog10PrimaryConc[iSec][jPri] += m_stoichMatrix[iSec][kDerivative] * dLog10PrimaryActCoeff_dIonicStrength[kDerivative] * primarySpeciesConcentration[jPri] *
- dIonicStrength_dPrimaryConc;
- }
-
- }
- secondarySpeciesConectration[iSec] = pow( 10, log10SecConc );
- }
-
-}
-
-void EquilibriumReactions::KernelWrapper::computeTotalConcAndDerivative( real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & secondarySpeciesConectration,
- arraySlice2d< real64 const > const & dLog10SecConc_dLog10PrimaryConc,
- arraySlice1d< real64 > const & totalConc,
- arraySlice2d< real64 > const & dTotalConc_dLog10PrimaryConc ) const
-
-
-{
- GEOS_UNUSED_VAR( temperature );
-
- // This function computes the total concentration and its derivative with respect to log10(basis species concentrations).
- for( int iPri = 0; iPri < m_numPrimarySpecies; iPri++ )
- {
- totalConc[iPri] = primarySpeciesConcentration[iPri];
- // d(total concentration)/d(log10(concentration))
- dTotalConc_dLog10PrimaryConc[iPri][iPri] = log( 10.0 ) * primarySpeciesConcentration[iPri];
- // contribution from all dependent species
- for( int jSec = 0; jSec < m_numSecondarySpecies; jSec++ )
- {
- totalConc[iPri] += m_stoichMatrix[jSec][iPri] * secondarySpeciesConectration[jSec];
- for( int kDerivative = 0; kDerivative < m_numPrimarySpecies; kDerivative++ )
- {
- // add contribution to the derivtive from dependent species via the chain rule
- dTotalConc_dLog10PrimaryConc[iPri][kDerivative] += m_stoichMatrix[jSec][iPri] * log( 10.0 ) *
- secondarySpeciesConectration[jSec] * dLog10SecConc_dLog10PrimaryConc[jSec][kDerivative];
- }
- }
- }
-}
-
-void EquilibriumReactions::KernelWrapper::
- updatePrimarySpeciesConcentrations( arraySlice1d< real64 const > const solution,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & primarySpeciesConcentration ) const
-{
- for( integer i = 0; i < m_numPrimarySpecies; i++ )
- {
- primarySpeciesConcentration[i] *= pow( 10, solution[i] );
- }
-}
-
-void EquilibriumReactions::KernelWrapper::setInitialGuess( arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesTotalConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & primarySpeciesConcentration ) const
-{
- for( integer i = 0; i < m_numPrimarySpecies; i++ )
- {
- primarySpeciesConcentration[i] = primarySpeciesTotalConcentration[i];
- }
- real64 const hPlusConcentration = 2*primarySpeciesConcentration[2]-2*primarySpeciesConcentration[3]-primarySpeciesConcentration[4]+2*primarySpeciesConcentration[5]+primarySpeciesConcentration[6];
- if( hPlusConcentration < 0 )
- {
- primarySpeciesConcentration[0] = -hPlusConcentration;
- }
- else
- {
- primarySpeciesConcentration[0] = 1e-7;
- }
-
-}
-
-
-} // end namespace chemicalReactions
-
-} // namespace constitutive
-
-} // end namespace geos
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp
deleted file mode 100644
index e3908d4df7d..00000000000
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/EquilibriumReactions.hpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * ------------------------------------------------------------------------------------------------------------
- * 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 EquilibriumReactions.hpp
- */
-
-#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_CHEMICALREACTIONS_EQUILIBRIUMREACTIONS_HPP_
-#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_CHEMICALREACTIONS_EQUILIBRIUMREACTIONS_HPP_
-
-#include "ReactionsBase.hpp"
-
-#include "constitutive/fluid/multifluid/Layouts.hpp"
-#include "constitutive/fluid/multifluid/MultiFluidConstants.hpp"
-
-namespace geos
-{
-
-namespace constitutive
-{
-
-namespace chemicalReactions
-{
-
-class EquilibriumReactions : public ReactionsBase
-{
-public:
-
- EquilibriumReactions( string const & name, integer const numPrimarySpecies, integer const numSecSpecies );
-
- class KernelWrapper final : public ReactionsBase::KernelWrapper
- {
-public:
-
- KernelWrapper( integer const numPrimarySpecies,
- integer const numSecondarySpecies,
- arrayView1d< real64 > const & log10EqConst,
- arrayView2d< real64 > const & stoichMatrix,
- arrayView1d< integer > const & chargePrimary,
- arrayView1d< integer > const & chargeSec,
- arrayView1d< real64 > const & ionSizePrimary,
- arrayView1d< real64 > const & ionSizeSec,
- real64 const DebyeHuckelA,
- real64 const DebyeHuckelB,
- real64 const WATEQBDot ):
- ReactionsBase::KernelWrapper( numPrimarySpecies,
- numSecondarySpecies,
- log10EqConst,
- stoichMatrix,
- chargePrimary,
- chargeSec,
- ionSizePrimary,
- ionSizeSec,
- DebyeHuckelA,
- DebyeHuckelB,
- WATEQBDot )
- {}
-
- /**
- * @brief Construct a new update Concentrations object
- *
- * @param temperature
- * @param totalConc
- * @param dLog10PrimaryConc_dTotalConc
- */
- void updateConcentrations( real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesTotalConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & primarySpeciesContentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration ) const;
-private:
-
- void assembleEquilibriumReactionSystem( real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesTotalConcentration,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration,
- arraySlice2d< real64 > const & matrix,
- arraySlice1d< real64 > const & rhs ) const;
-
- void computeSeondarySpeciesConcAndDerivative( real64 const temperature,
- arraySlice1d< real64 const > const & log10PrimaryActCoeff,
- arraySlice1d< real64 const > const & dLog10PrimaryActCoeff_dIonicStrength,
- arraySlice1d< real64 const > const & log10SecActCoeff,
- arraySlice1d< real64 const > const & dLog10SecActCoeff_dIonicStrength,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration,
- arraySlice2d< real64 > const & dLog10SecConc_dLog10PrimaryConc ) const;
-
- void computeTotalConcAndDerivative( real64 const temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration,
- arraySlice2d< real64 const > const & dLog10SecConc_dLog10PrimaryConc,
- arraySlice1d< real64 > const & totalConc,
- arraySlice2d< real64 > const & dTotalConc_dLog10PrimaryConc ) const;
-
- void updatePrimarySpeciesConcentrations( arraySlice1d< real64 const > const solution,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & primarySpeciesConcentration ) const;
-
- void setInitialGuess( arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesTotalConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & primarySpeciesConcentration ) const;
-
- static constexpr integer m_maxNumIterations = MultiFluidConstants::maxNewtonIterations;
- static constexpr real64 m_newtonTol = 1e-6;
- };
-
-/**
- * @brief Create an update kernel wrapper.
- * @return the wrapper
- */
- KernelWrapper createKernelWrapper() const;
-
-};
-
-
-} // end namespace chemicalReactions
-
-} // end namespace constitutive
-
-} // end namespace geos
-
-#endif //GEOS_CONSTITUTIVE_FLUID_CHEMICALREACTIONS_REQUILIBRIUMREACTIONS_HPP_
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.cpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.cpp
deleted file mode 100644
index 5009c9fbeae..00000000000
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * ------------------------------------------------------------------------------------------------------------
- * 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 KineticReactions.cpp
- */
-
-#include "constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp"
-#include "functions/FunctionManager.hpp"
-#include "common/Units.hpp"
-
-namespace geos
-{
-
-using namespace stringutilities;
-
-namespace constitutive
-{
-
-namespace chemicalReactions
-{
-
-KineticReactions::KineticReactions( string const & name, integer const numPrimarySpecies, integer const numSecSpecies, integer const numKineticReactions ):
- ReactionsBase( name, numPrimarySpecies, numSecSpecies ),
- m_numKineticReactions( numKineticReactions )
-{
-
- // Stochiometric Matrix for the kinetic reactions (in terms of primary species only)
- // First index: 0 = Ca(OH)2 dissolution, 1 = CaCO3 dissolution
- // Second index: 0 = H+, 1 = HCO3-, 2 = Ca+2, 3 = SO4-2, 4 = Cl-, 5 = Mg+2, 6 = Na+1
- m_stoichMatrix.resize( m_numKineticReactions, m_numPrimarySpecies );
- m_stoichMatrix[0][0] = -2;
- m_stoichMatrix[0][2] = 1;
- m_stoichMatrix[1][0] = -1;
- m_stoichMatrix[1][1] = 1;
- m_stoichMatrix[1][2] = 1;
-
- // Equilibrium Constant
- m_log10EqConst.resize( m_numKineticReactions );
- m_log10EqConst[0] = 20.19;
- m_log10EqConst[1] = 1.32;
-
- // Rate Constant
- // have to check the values as the functional form of the rate equation here differs from the implementation in GEOS
- m_reactionRateConstant.resize( m_numKineticReactions );
- m_reactionRateConstant[0] = 9.95e-1;
- m_reactionRateConstant[1] = 9.95e-3;
- // Here we should either read the database or the input values.
-
- m_specificSurfaceArea = 1.0;
-}
-
-KineticReactions::KernelWrapper KineticReactions::createKernelWrapper() const
-{
- return KernelWrapper( m_numPrimarySpecies,
- m_numSecondarySpecies,
- m_numKineticReactions,
- m_log10EqConst,
- m_stoichMatrix,
- m_chargePrimary,
- m_chargeSec,
- m_ionSizePrimary,
- m_ionSizeSec,
- m_DebyeHuckelA,
- m_DebyeHuckelB,
- m_WATEQBDot,
- m_reactionRateConstant,
- m_specificSurfaceArea );
-}
-
-// function to the reaction rate. Includes impact of temperature, concentration, surface area, volume fraction and porosity
-void KineticReactions::KernelWrapper::computeReactionRates( real64 const & temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & reactionRates ) const
-{
- /// 1. Create local vectors
- stackArray1d< real64, ReactionsBase::maxNumPrimarySpecies > log10PrimaryActCoeff( m_numPrimarySpecies );
- stackArray1d< real64, ReactionsBase::maxNumSecondarySpecies > log10SecActCoeff( m_numSecondarySpecies );
-
- real64 ionicStrength = 0.0;
- stackArray1d< real64, ReactionsBase::maxNumPrimarySpecies > dIonicStrength_dPrimaryConcentration( m_numPrimarySpecies );
- stackArray1d< real64, ReactionsBase::maxNumPrimarySpecies > dLog10PrimaryActCoeff_dIonicStrength( m_numPrimarySpecies );
- stackArray1d< real64, ReactionsBase::maxNumSecondarySpecies > dLog10SecActCoeff_dIonicStrength( m_numSecondarySpecies );
-
- /// 2. Compute activity coefficients
- computeIonicStrength( primarySpeciesConcentration,
- secondarySpeciesConcentration,
- ionicStrength );
-
- computeLog10ActCoefBDotModel( temperature,
- ionicStrength,
- log10PrimaryActCoeff,
- dLog10PrimaryActCoeff_dIonicStrength,
- log10SecActCoeff,
- dLog10SecActCoeff_dIonicStrength );
-
-
- /// 3. Compute reaction rates
- for( int iRxn = 0; iRxn < m_numKineticReactions; iRxn++ )
- {
- real64 saturationIndex = -m_log10EqConst[iRxn];
-
- for( int iPri = 0; iPri < m_numPrimarySpecies; ++iPri )
- {
- saturationIndex += m_stoichMatrix[iRxn][iPri] * log10( primarySpeciesConcentration[iPri] );
- saturationIndex += m_stoichMatrix[iRxn][iPri] * log10PrimaryActCoeff[iPri];
- }
-
- reactionRates[iRxn] = m_specificSurfaceArea * (1.0 - pow( 10, saturationIndex ) ) * m_reactionRateConstant[iRxn];
- }
-}
-
-} // end namespace chemicalReactions
-
-} // namespace constitutive
-
-} // end namespace geos
-
-/*
- for( localIndex ir = 0; ir < NReaction; ++ir )
- {
-
- for( localIndex ic = 0; ic < kineticReaction.stochs.size(); ++ic )
- {
- dSIndex[id] = kineticReaction.stochs[ic];
-
- }
-
-
- for( localIndex ic = 0; ic < NBasis; ++ic )
- {
-
- dKineticReactionRate_dConc[ir][ic] = S * kineticReaction.rateConst * rateTemp * pow( 10.0, SIndex ) * log( 10.0 ) * dSIndex[ic];
-
- }
-
- }
-
-
- for( localIndex ir = 0; ir < NReaction; ++ir )
- {
-
- for( localIndex i = 0; i < (kineticReaction.stochs).size(); ++i )
- {
-
- localIndex ic = basisSpeciesIndices[i];
-
- kineticSpeciesReactionRate[ic] += -(kineticReaction.stochs)[i] * kineticReactionRate[ir];
-
- for( localIndex id = 0; id < NBasis; ++id )
- {
-
- dKineticSpeciesReactionRate_dConc[ic][id] += -(kineticReaction.stochs)[i] * dKineticReactionRate_dConc[ir][id];
-
- }
-
- }
-
- }
-
- }
- // arraySlice1d< real64 const > const & concentration,
- // arraySlice1d< real64 const > const & surfaceArea0,
- // arraySlice1d< real64 const > const & volumeFraction0,
- // arraySlice1d< real64 const > const & volumeFraction,
- // real64 const & porosity0,
- // real64 const & porosity,
- // arraySlice1d< real64 > const & kineticReactionRate )
- // {
- // for( localIndex ir = 0; ir < kineticReactionArray.size(); ++ir )
- // {
- // const KineticReaction & kineticReaction = kineticReactionArray[ir];
- // const array1d< localIndex > & basisSpeciesIndices = kineticReaction.basisSpeciesIndices;
- // // calculate saturation index
- // real64 SIndex = -kineticReaction.logK;
- // for( localIndex ic = 0; ic < kineticReaction.stochs.size(); ++ic )
- // {
- // SIndex += kineticReaction.stochs[ic] * concentration[basisSpeciesIndices[ic] ]; // Check that the input "concentration" is
- // // actually ln(activity
- // coefficient*concentration)
- // }
- // // surface area is assumed to scale with the volume fraction. Check whether this is the volume fraction of the mineral
- // // dissolving/precipitating. Not sure why porosity is included.
- // real64 S = surfaceArea0[ir] * pow( volumeFraction[ir] / volumeFraction0[ir], 2.0/3.0 ) * pow( porosity / porosity0, 2.0/3.0 );
- // // computing the rate at the correct temperature. Looks like EQ36 database has it at 298.15 K
- // real64 rateTemp = exp( -kineticReaction.E / RConst * (1.0 / units::convertCToK( temperature ) - 1.0 / 298.15));
- // real64 SS = (pow( 10.0, SIndex ) - 1.0);
- // kineticReactionRate[ir] = S * kineticReaction.rateConst * rateTemp * SS;
- //}
-
-
- */
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp
deleted file mode 100644
index 7c2ff5bf64a..00000000000
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/KineticReactions.hpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * ------------------------------------------------------------------------------------------------------------
- * 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 EquilibriumReaction.hpp
- */
-
-#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_CHEMICALREACTIONS_REACTIONBASE_HPP_
-#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_CHEMICALREACTIONS_REACTIONBASE_HPP_
-
-#include "ReactionsBase.hpp"
-
-#include "constitutive/fluid/multifluid/Layouts.hpp"
-#include "common/PhysicsConstants.hpp"
-
-namespace geos
-{
-
-namespace constitutive
-{
-
-namespace chemicalReactions
-{
-
-class KineticReactions : public ReactionsBase
-{
-public:
-
- KineticReactions( string const & name, integer const numPrimarySpecies, integer const numSecSpecies, integer const numKineticReactions );
-
- class KernelWrapper final : public ReactionsBase::KernelWrapper
- {
-public:
-
- static constexpr real64 RConst = constants::gasConstant;
-
- KernelWrapper( integer const numPrimarySpecies,
- integer const numSecondarySpecies,
- integer const numKineticReactions,
- arrayView1d< real64 > const & log10EqConst,
- arrayView2d< real64 > const & stoichMatrix,
- arrayView1d< integer > const & chargePrimary,
- arrayView1d< integer > const & chargeSec,
- arrayView1d< real64 > const & ionSizePrimary,
- arrayView1d< real64 > const & ionSizeSec,
- real64 const DebyeHuckelA,
- real64 const DebyeHuckelB,
- real64 const WATEQBDot,
- arrayView1d< real64 > const & reactionRateConstant,
- real64 const specificSurfaceArea ):
- ReactionsBase::KernelWrapper( numPrimarySpecies,
- numSecondarySpecies,
- log10EqConst,
- stoichMatrix,
- chargePrimary,
- chargeSec,
- ionSizePrimary,
- ionSizeSec,
- DebyeHuckelA,
- DebyeHuckelB,
- WATEQBDot ),
- m_reactionRateConstant( reactionRateConstant ),
- m_numKineticReactions( numKineticReactions ),
- m_specificSurfaceArea( specificSurfaceArea )
- {}
-
- /**
- * @brief Compute kinetic reaction rates.
- *
- * @param temperature
- * @param primarySpeciesConcentration concentration of the primary species
- * @param log10PrimaryActCoeff
- * @param specificSurfaceArea the surface area available per unit volume
- * @param reactionRates
- */
- void computeReactionRates( real64 const & temperature,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration,
- arraySlice1d< real64, compflow::USD_COMP - 1 > const & reactionRates ) const;
-
-private:
-
- arrayView1d< real64 > m_reactionRateConstant;
-
- integer m_numKineticReactions;
-
- real64 m_specificSurfaceArea;
-
- };
-
- /**
- * @brief Create an update kernel wrapper.
- * @return the wrapper
- */
- KernelWrapper createKernelWrapper() const;
-
-private:
-
- array1d< real64 > m_reactionRateConstant;
-
- integer m_numKineticReactions;
-
- real64 m_specificSurfaceArea;
-};
-
-} // end namespace chemicalReactions
-
-} // end namespace constitutive
-
-} // end namespace geos
-
-#endif //GEOS_CONSTITUTIVE_FLUID_CHEMICALREACTIONS_REACTIONBASE_HPP_
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.cpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.cpp
deleted file mode 100644
index df579b3587e..00000000000
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * ------------------------------------------------------------------------------------------------------------
- * 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 EquilibriumReaction.cpp
- */
-
-#include "constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.hpp"
-
-#include "functions/FunctionManager.hpp"
-
-namespace geos
-{
-
-using namespace stringutilities;
-
-namespace constitutive
-{
-
-namespace chemicalReactions
-{
-
-ReactionsBase::ReactionsBase( string const & name, integer const numPrimarySpecies, integer const numSecSpecies ):
- m_name( name ),
- m_numPrimarySpecies( numPrimarySpecies ),
- m_numSecondarySpecies( numSecSpecies )
-{
- // Activity coefficient related constants
- m_DebyeHuckelA = 0.5465;
- m_DebyeHuckelB = 0.3346;
- m_WATEQBDot = 0.0438;
-
- m_ionSizePrimary.resize( m_numPrimarySpecies );
- m_ionSizePrimary[0] = 9.00;
- m_ionSizePrimary[1] = 4.00;
- m_ionSizePrimary[2] = 6.00;
- m_ionSizePrimary[3] = 4.00;
- m_ionSizePrimary[4] = 3.00;
- m_ionSizePrimary[5] = 8.00;
- m_ionSizePrimary[6] = 4.00;
-
- m_ionSizeSec.resize( m_numSecondarySpecies );
- m_ionSizeSec[0] = 3.50;
- m_ionSizeSec[1] = 3.00;
- m_ionSizeSec[2] = 4.50;
- m_ionSizeSec[3] = 3.00;
- m_ionSizeSec[4] = 4.00;
- m_ionSizeSec[5] = 3.00;
- m_ionSizeSec[6] = 3.00;
- m_ionSizeSec[7] = 4.00;
- m_ionSizeSec[8] = 3.00;
- m_ionSizeSec[9] = 3.00;
- m_ionSizeSec[10] = 4.00;
-
- m_chargePrimary.resize( m_numPrimarySpecies );
- m_chargePrimary[0] = 1;
- m_chargePrimary[1] = -1;
- m_chargePrimary[2] = 2;
- m_chargePrimary[3] = -2;
- m_chargePrimary[4] = -1;
- m_chargePrimary[5] = 2;
- m_chargePrimary[6] = 1;
-
- m_chargeSec.resize( m_numSecondarySpecies );
- m_chargeSec[0] = -1;
- m_chargeSec[1] = 0;
- m_chargeSec[2] = -2;
- m_chargeSec[3] = 0;
- m_chargeSec[4] = 1;
- m_chargeSec[5] = 0;
- m_chargeSec[6] = 0;
- m_chargeSec[7] = 1;
- m_chargeSec[8] = 0;
- m_chargeSec[9] = 0;
- m_chargeSec[10] = -1;
-
-}
-
-void ReactionsBase::KernelWrapper::computeLog10ActCoefBDotModel( real64 const temperature,
- real64 const ionicStrength,
- arraySlice1d< real64 > const & log10PrimaryActCoeff,
- arraySlice1d< real64 > const & dLog10PrimaryActCoeff_dIonicStrength,
- arraySlice1d< real64 > const & log10SecActCoeff,
- arraySlice1d< real64 > const & dLog10SecActCoeff_dIonicStrength ) const
-{
- // Compute log10(ActivityCoefficient) for basis and dependent species along with their
- // derivatives with respect to Ionic strength using the B-Dot Model
- // which is the same as the Extended Debye-Huckel model in GEOS.
- // localIndex const NBasis = m_numPrimarySpecies;
- // localIndex const NDependent = m_numSecondarySpecies;
-
- GEOS_UNUSED_VAR( temperature );
-
- for( localIndex i = 0; i < m_numPrimarySpecies; ++i )
- {
- log10PrimaryActCoeff[i] = m_WATEQBDot * ionicStrength - m_DebyeHuckelA * m_chargePrimary[i] * m_chargePrimary[i] * sqrt( ionicStrength ) /
- (1.0 + m_ionSizePrimary[i] * m_DebyeHuckelB * sqrt( ionicStrength ));
- dLog10PrimaryActCoeff_dIonicStrength[i] = m_WATEQBDot - m_DebyeHuckelA * m_chargePrimary[i] * m_chargePrimary[i] *
- (0.5 / sqrt( ionicStrength ) / (1.0 + m_ionSizePrimary[i] * m_DebyeHuckelB * sqrt( ionicStrength )) - 0.5 * m_ionSizePrimary[i] * m_DebyeHuckelB /
- (1.0 + m_ionSizePrimary[i] * m_DebyeHuckelB * sqrt( ionicStrength )) /
- (1.0 + m_ionSizePrimary[i] * m_DebyeHuckelB * sqrt( ionicStrength )));
-// log10PrimaryActCoeff[i] = 0;
-// dLog10PrimaryActCoeff_dIonicStrength[i] = 0;
- }
- for( localIndex i = 0; i < m_numSecondarySpecies; ++i )
- {
- log10SecActCoeff[i] = m_WATEQBDot * ionicStrength - m_DebyeHuckelA * m_chargeSec[i] * m_chargeSec[i] * sqrt( ionicStrength ) /
- (1.0 + m_ionSizeSec[i] * m_DebyeHuckelB * sqrt( ionicStrength ));
- dLog10SecActCoeff_dIonicStrength[i] = m_WATEQBDot - m_DebyeHuckelA * m_chargeSec[i] * m_chargeSec[i] *
- (0.5 / sqrt( ionicStrength ) / (1.0 + m_ionSizeSec[i] * m_DebyeHuckelB * sqrt( ionicStrength )) - 0.5 * m_ionSizeSec[i] * m_DebyeHuckelB /
- (1.0 + m_ionSizeSec[i] * m_DebyeHuckelB * sqrt( ionicStrength )) /
- (1.0 + m_ionSizeSec[i] * m_DebyeHuckelB * sqrt( ionicStrength )));
-// log10SecActCoeff[i] = 0;
-// dLog10SecActCoeff_dIonicStrength[i] = 0;
- }
-}
-
-void ReactionsBase::KernelWrapper::computeIonicStrength( arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration,
- real64 & ionicStrength ) const
-{
- //get ionic strength
- ionicStrength = 0.0;
- // Primary species
- for( localIndex i = 0; i < m_numPrimarySpecies; ++i )
- {
- ionicStrength += 0.5 * m_chargePrimary[i] * m_chargePrimary[i] * primarySpeciesConcentration[i];
- }
- // Secondary species
- for( int j = 0; j < m_numSecondarySpecies; ++j )
- {
- ionicStrength += 0.5 * m_chargeSec[j] * m_chargeSec[j] * secondarySpeciesConcentration[j];
- }
-}
-
-} // end namespace chemicalReactions
-
-} // namespace constitutive
-
-} // end namespace geos
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.hpp b/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.hpp
deleted file mode 100644
index 8b3e01b335f..00000000000
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/chemicalReactions/ReactionsBase.hpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * ------------------------------------------------------------------------------------------------------------
- * 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 ReactionsBase.hpp
- */
-
-#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_CHEMICALREACTIONS_REACTIONSBASE_HPP_
-#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_CHEMICALREACTIONS_REACTIONSBASE_HPP_
-
-#include "dataRepository/ObjectCatalog.hpp"
-
-namespace geos
-{
-
-namespace constitutive
-{
-
-namespace chemicalReactions
-{
-
-class ReactionsBase
-{
-public:
-
- ReactionsBase( string const & name, integer const numPrimarySpecies, integer const numSecSpecies );
-
- virtual ~ReactionsBase() = default;
-
- constexpr static integer maxNumPrimarySpecies = 12;
- constexpr static integer maxNumSecondarySpecies = 15;
-
- string const & reactionName() const { return m_name; }
-
-protected:
- /// Name the solubility model
- string m_name;
-
- integer m_numPrimarySpecies;
-
- integer m_numSecondarySpecies;
-
- /// Array storing the name of the components
- string_array m_componentNames;
-
- /// Array storing the component molar weights
- array1d< real64 > m_componentMolarWeight;
-
- array1d< real64 > m_log10EqConst;
-
- array2d< real64 > m_stoichMatrix;
-
- array1d< integer > m_chargePrimary;
- array1d< integer > m_chargeSec;
-
- array1d< real64 > m_ionSizePrimary;
- array1d< real64 > m_ionSizeSec;
-
- real64 m_DebyeHuckelA;
- real64 m_DebyeHuckelB;
- real64 m_WATEQBDot;
-
- class KernelWrapper
- {
-public:
-
- /**
- * @brief Construct a new Kernel Wrapper object
- *
- * @param log10EqConst
- * @param stoichMatrix
- * @param chargePrimary
- * @param chargeSec
- * @param m_ionSizePrimary
- * @param ionSizeSec
- * @param DebyeHuckelA
- * @param DebyeHuckelB
- * @param WATEQBDot
- */
- KernelWrapper( integer const numPrimarySpecies,
- integer const numSecondarySpecies,
- arrayView1d< real64 > const & log10EqConst,
- arrayView2d< real64 > const & stoichMatrix,
- arrayView1d< integer > const & chargePrimary,
- arrayView1d< integer > const & chargeSec,
- arrayView1d< real64 > const & ionSizePrimary,
- arrayView1d< real64 > const & ionSizeSec,
- real64 const DebyeHuckelA,
- real64 const DebyeHuckelB,
- real64 const WATEQBDot ):
- m_numPrimarySpecies( numPrimarySpecies ),
- m_numSecondarySpecies( numSecondarySpecies ),
- m_log10EqConst( log10EqConst ),
- m_stoichMatrix( stoichMatrix ),
- m_chargePrimary( chargePrimary ),
- m_chargeSec( chargeSec ),
- m_ionSizePrimary( ionSizePrimary ),
- m_ionSizeSec( ionSizeSec ),
- m_DebyeHuckelA( DebyeHuckelA ),
- m_DebyeHuckelB( DebyeHuckelB ),
- m_WATEQBDot( WATEQBDot )
- {}
-
-protected:
-
- /**
- * @brief
- *
- * @param temperature
- * @param ionicStrength
- * @param log10PrimaryActCoeff
- * @param dLog10PrimaryActCoeff_dIonicStrength
- * @param log10SecActCoeff
- * @param dLog10SecActCoeff_dIonicStrength
- */
- void computeLog10ActCoefBDotModel( real64 const temperature,
- real64 const ionicStrength,
- arraySlice1d< real64 > const & log10PrimaryActCoeff,
- arraySlice1d< real64 > const & dLog10PrimaryActCoeff_dIonicStrength,
- arraySlice1d< real64 > const & log10SecActCoeff,
- arraySlice1d< real64 > const & dLog10SecActCoeff_dIonicStrength ) const;
- /**
- * @brief
- *
- * @return
- */
- void computeIonicStrength( arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & primarySpeciesConcentration,
- arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & secondarySpeciesConcentration,
- real64 & ionicStrength ) const;
-
-
- /// Hard coding the example case - eventually would have to be changed such that it is read from an input file
- integer m_numPrimarySpecies; // Currently not including H2O and O2gas
- integer m_numSecondarySpecies;
-
- arrayView1d< real64 > m_log10EqConst;
- arrayView2d< real64 > m_stoichMatrix;
-
- arrayView1d< integer > m_chargePrimary;
- arrayView1d< integer > m_chargeSec;
-
- arrayView1d< real64 > m_ionSizePrimary;
- arrayView1d< real64 > m_ionSizeSec;
-
- real64 m_DebyeHuckelA;
- real64 m_DebyeHuckelB;
- real64 m_WATEQBDot;
- };
-
-};
-
-} // end namespace chemicalReactions
-
-} // end namespace constitutive
-
-} // end namespace geos
-
-#endif //GEOS_CONSTITUTIVE_FLUID_CHEMICALREACTIONS_REACTIONSBASE_HPP_
diff --git a/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveFluidFields.hpp b/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveFluidFields.hpp
new file mode 100644
index 00000000000..54e1c9a1fc2
--- /dev/null
+++ b/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveFluidFields.hpp
@@ -0,0 +1,123 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ReactiveFluidFields.hpp
+ */
+
+#ifndef GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVEFLUIDFIELDS_HPP_
+#define GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVEFLUIDFIELDS_HPP_
+
+#include "constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp"
+#include "mesh/MeshFields.hpp"
+
+namespace geos
+{
+
+namespace fields
+{
+
+namespace reactivefluid
+{
+
+using array3dLayoutSpecies = array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES >;
+using array4dLayoutSpecies_dC = array4d< real64, constitutive::reactivefluid::LAYOUT_SPECIES_DC >;
+
+DECLARE_FIELD( initialPrimarySpeciesConcentration,
+ "initialPrimarySpeciesConcentration",
+ array3dLayoutSpecies,
+ 1e-16,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "initialPrimarySpeciesConcentration" );
+
+DECLARE_FIELD( primarySpeciesAggregateConcentration,
+ "primarySpeciesAggregateConcentration",
+ array3dLayoutSpecies,
+ 1e-16,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "primarySpeciesAggregateConcentration" );
+
+DECLARE_FIELD( primarySpeciesAggregateConcentration_n,
+ "primarySpeciesAggregateConcentration_n",
+ array3dLayoutSpecies,
+ 1e-16,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "primarySpeciesAggregateConcentration at the previous timestep" );
+
+DECLARE_FIELD( primarySpeciesMobileAggregateConcentration,
+ "primarySpeciesMobileAggregateConcentration",
+ array3dLayoutSpecies,
+ 1e-16,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "primarySpeciesMobileAggregateConcentration" );
+
+DECLARE_FIELD( dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ "dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations",
+ array4dLayoutSpecies_dC,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Deivatives of primarySpeciesAggregateConcentration w.r.t log primary species concentration" );
+
+DECLARE_FIELD( dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ "dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations",
+ array4dLayoutSpecies_dC,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Deivatives of primarySpeciesMobileAggregateConcentration w.r.t log primary species concentration" );
+
+DECLARE_FIELD( secondarySpeciesConcentration,
+ "secondarySpeciesConcentration",
+ array3dLayoutSpecies,
+ 1e-16,
+ NOPLOT,
+ WRITE_AND_READ,
+ "secondarySpeciesConcentration" );
+
+DECLARE_FIELD( kineticReactionRates,
+ "kineticReactionRates",
+ array3dLayoutSpecies,
+ 0,
+ NOPLOT,
+ WRITE_AND_READ,
+ "kineticReactionRates" );
+
+DECLARE_FIELD( aggregateSpeciesRates,
+ "aggregateSpeciesRates",
+ array3dLayoutSpecies,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "aggregateSpeciesRates" );
+
+DECLARE_FIELD( dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations,
+ "dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations",
+ array4dLayoutSpecies_dC,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Deivatives of aggregate concentration rates w.r.t log primary species concentration" );
+}
+
+}
+
+}
+
+#endif // GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVEFLUIDFIELDS_HPP_
diff --git a/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp b/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp
new file mode 100644
index 00000000000..5949d33e9ab
--- /dev/null
+++ b/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp
@@ -0,0 +1,114 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 Layouts.hpp
+ */
+
+#ifndef GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVEFLUIDLAYOUTS_HPP
+#define GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVEFLUIDLAYOUTS_HPP
+
+#include "common/DataTypes.hpp"
+#include "common/GeosxConfig.hpp"
+
+#include "LvArray/src/typeManipulation.hpp"
+#include "RAJA/RAJA.hpp"
+
+namespace geos
+{
+namespace constitutive
+{
+
+namespace reactivefluid
+{
+struct DerivativeOffset
+{
+ /// index of derivative wrt pressure
+ static integer constexpr dP = 0;
+ /// index of derivative wrt temperature
+ static integer constexpr dT = 1;
+ /// index of first derivative wrt compositions
+ static integer constexpr dC = 2;
+};
+
+/// indices of pressure, temperature, and composition derivatives
+template< integer NC, integer IS_THERMAL >
+struct DerivativeOffsetC {};
+
+template< integer NC >
+struct DerivativeOffsetC< NC, 1 >
+{
+ /// index of derivative wrt pressure
+ static integer constexpr dP = 0;
+ /// index of derivative wrt temperature
+ static integer constexpr dT = dP + 1;
+ /// index of first derivative wrt compositions
+ static integer constexpr dC = dP+2;
+ /// number of derivatives
+ static integer constexpr nDer = NC + 2;
+};
+template< integer NC >
+struct DerivativeOffsetC< NC, 0 >
+{
+ /// index of derivative wrt pressure
+ static integer constexpr dP = 0;
+ /// index of first derivative wrt compositions
+ static integer constexpr dC = dP+1;
+ /// number of derivatives
+ static integer constexpr nDer = NC + 1;
+};
+
+ #if defined( GEOS_USE_DEVICE )
+
+/// Constitutive model species variable array array layout
+using LAYOUT_SPECIES = RAJA::PERM_JKI;
+/// Constitutive model species derivative of species variable array layout
+using LAYOUT_SPECIES_DC = RAJA::PERM_JKLI;
+
+/// Constitutive model fluid property array layout
+using LAYOUT_FLUID = RAJA::PERM_JI;
+/// Constitutive model fluid property species derivative array layout
+using LAYOUT_FLUID_DC = RAJA::PERM_JKI;
+
+ #else
+
+/// Constitutive model species variable array array layout
+using LAYOUT_SPECIES = RAJA::PERM_IJK;
+/// Constitutive model species derivative of species variable array layout
+using LAYOUT_SPECIES_DC = RAJA::PERM_IJKL;
+
+/// Constitutive model fluid property array layout
+using LAYOUT_FLUID = RAJA::PERM_IJ;
+/// Constitutive model fluid property species derivative array layout
+using LAYOUT_FLUID_DC = RAJA::PERM_IJK;
+
+ #endif
+
+
+/// Constitutive model phase composition unit stride dimension
+static constexpr int USD_SPECIES = LvArray::typeManipulation::getStrideOneDimension( LAYOUT_SPECIES{} );
+/// Constitutive model phase composition compositional derivative unit stride dimension
+static constexpr int USD_SPECIES_DC = LvArray::typeManipulation::getStrideOneDimension( LAYOUT_SPECIES_DC{} );
+
+/// Constitutive model fluid property unit stride dimension
+static constexpr int USD_FLUID = LvArray::typeManipulation::getStrideOneDimension( LAYOUT_FLUID{} );
+/// Constitutive model fluid property compositional derivative unit stride dimension
+static constexpr int USD_FLUID_DC = LvArray::typeManipulation::getStrideOneDimension( LAYOUT_FLUID_DC{} );
+
+} // namespace reactivefluid
+} // namespace constitutive
+} // namespace geos
+
+#endif //GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVEFLUIDLAYOUTS_HPP
diff --git a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidSelector.hpp b/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveFluidSelector.hpp
similarity index 55%
rename from src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidSelector.hpp
rename to src/coreComponents/constitutive/fluid/reactivefluid/ReactiveFluidSelector.hpp
index 03439e9629b..8a3ef4b4602 100644
--- a/src/coreComponents/constitutive/fluid/multifluid/reactive/ReactiveFluidSelector.hpp
+++ b/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveFluidSelector.hpp
@@ -16,13 +16,11 @@
/**
* @file ReactiveFluidSelector.hpp
*/
-#ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_REACTIVEFLUIDSELECTOR_HPP_
-#define GEOS_CONSTITUTIVE_FLUID_MULTIFLUID_REACTIVE_REACTIVEFLUIDSELECTOR_HPP_
+#ifndef GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVEFLUIDSELECTOR_HPP_
+#define GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVEFLUIDSELECTOR_HPP_
#include "constitutive/ConstitutivePassThruHandler.hpp"
-#include "constitutive/fluid/multifluid/reactive/ReactiveBrineFluid.hpp"
-
-#include "common/GeosxConfig.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.hpp"
namespace geos
{
@@ -31,23 +29,23 @@ namespace constitutive
{
template< typename LAMBDA >
-void constitutiveUpdatePassThru( ReactiveMultiFluid const & fluid,
+void constitutiveUpdatePassThru( SingleFluidBase const & fluid,
LAMBDA && lambda )
{
- ConstitutivePassThruHandler< ReactiveBrine,
- ReactiveBrineThermal >::execute( fluid, std::forward< LAMBDA >( lambda ) );
+ ConstitutivePassThruHandler< reactivefluid::ReactiveCompressibleSinglePhaseFluid,
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >::execute( fluid, std::forward< LAMBDA >( lambda ) );
}
template< typename LAMBDA >
-void constitutiveUpdatePassThru( ReactiveMultiFluid & fluid,
+void constitutiveUpdatePassThru( SingleFluidBase & fluid,
LAMBDA && lambda )
{
- ConstitutivePassThruHandler< ReactiveBrine,
- ReactiveBrineThermal >::execute( fluid, std::forward< LAMBDA >( lambda ) );
+ ConstitutivePassThruHandler< reactivefluid::ReactiveCompressibleSinglePhaseFluid,
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >::execute( fluid, std::forward< LAMBDA >( lambda ) );
}
} // namespace constitutive
} // namespace geos
-#endif //GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUIDSELECTOR_HPP_
+#endif //GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVEFLUIDSELECTOR_HPP_
diff --git a/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.cpp b/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.cpp
new file mode 100644
index 00000000000..69b7b750934
--- /dev/null
+++ b/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.cpp
@@ -0,0 +1,168 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ReactiveSinglePhaseFluid.cpp
+ */
+#include "ReactiveSinglePhaseFluid.hpp"
+#include "ReactiveFluidFields.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+namespace constitutive
+{
+
+namespace reactivefluid
+{
+
+using namespace hpcReact::bulkGeneric;
+
+template< typename BASE >
+ReactiveSinglePhaseFluid< BASE >::
+ReactiveSinglePhaseFluid( string const & name, Group * const parent ):
+ BASE( name, parent )
+{
+
+ this->registerWrapper( viewKeyStruct::chemicalSystemNameString(), &m_chemicalSystemType ).
+ setInputFlag( InputFlags::REQUIRED ).
+ setDescription( "Chemical System type. Available options are: "
+ "``" + EnumStrings< ChemicalSystemType >::concat( "|" ) + "``" );
+
+ this->template registerField< fields::reactivefluid::initialPrimarySpeciesConcentration >( &m_initialPrimarySpeciesConcentration );
+ this->template registerField< fields::reactivefluid::secondarySpeciesConcentration >( &m_secondarySpeciesConcentration );
+ this->template registerField< fields::reactivefluid::primarySpeciesAggregateConcentration >( &m_primarySpeciesAggregateConcentration );
+ this->template registerField< fields::reactivefluid::primarySpeciesAggregateConcentration_n >( &m_primarySpeciesAggregateConcentration_n );
+ this->template registerField< fields::reactivefluid::primarySpeciesMobileAggregateConcentration >( &m_primarySpeciesMobileAggregateConcentration );
+ this->template registerField< fields::reactivefluid::dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations >(
+ &m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations );
+ this->template registerField< fields::reactivefluid::dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations >(
+ &m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations );
+ this->template registerField< fields::reactivefluid::kineticReactionRates >( &m_kineticReactionRates );
+ this->template registerField< fields::reactivefluid::aggregateSpeciesRates >( &m_aggregateSpeciesRates );
+ this->template registerField< fields::reactivefluid::dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations >( &m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations );
+}
+
+template< typename BASE >
+std::unique_ptr< ConstitutiveBase > ReactiveSinglePhaseFluid< BASE >::
+deliverClone( string const & name, Group * const parent ) const
+{
+ std::unique_ptr< ConstitutiveBase > clone = BASE::deliverClone( name, parent );
+
+ ReactiveSinglePhaseFluid & newConstitutiveRelation = dynamicCast< ReactiveSinglePhaseFluid & >( *clone );
+
+ newConstitutiveRelation.m_chemicalSystemType = m_chemicalSystemType;
+ newConstitutiveRelation.m_numPrimarySpecies = m_numPrimarySpecies;
+ newConstitutiveRelation.m_numSecondarySpecies = m_numSecondarySpecies;
+ newConstitutiveRelation.m_numKineticReactions = m_numKineticReactions;
+
+ return clone;
+}
+
+template< typename BASE >
+void ReactiveSinglePhaseFluid< BASE >::postInputInitialization()
+{
+ BASE::postInputInitialization();
+
+ switch( m_chemicalSystemType )
+ {
+ case ChemicalSystemType::ultramafic:
+ m_numPrimarySpecies = 9;
+ m_numSecondarySpecies = 16;
+ m_numKineticReactions = 5;
+ break;
+
+ case ChemicalSystemType::carbonate:
+ m_numPrimarySpecies = 7;
+ m_numSecondarySpecies = 10;
+ m_numKineticReactions = 1;
+ break;
+
+ case ChemicalSystemType::carbonateAllEquilibrium:
+ m_numPrimarySpecies = 7;
+ m_numSecondarySpecies = 11;
+ m_numKineticReactions = 0;
+ break;
+
+ case ChemicalSystemType::chainSerialAllKinetic:
+ m_numPrimarySpecies = 3;
+ m_numSecondarySpecies = 0;
+ m_numKineticReactions = 3;
+ break;
+
+ case ChemicalSystemType::momasMedium:
+ m_numPrimarySpecies = 5;
+ m_numSecondarySpecies = 9;
+ m_numKineticReactions = 1;
+ break;
+
+ default:
+ m_numPrimarySpecies = 5;
+ m_numSecondarySpecies = 7;
+ m_numKineticReactions = 0;
+ break;
+ }
+}
+
+template< typename BASE >
+void ReactiveSinglePhaseFluid< BASE >::saveConvergedState() const
+{
+ BASE::saveConvergedState();
+
+ m_primarySpeciesAggregateConcentration_n.setValues< parallelDevicePolicy<> >( m_primarySpeciesAggregateConcentration.toViewConst() );
+}
+
+template< typename BASE >
+void ReactiveSinglePhaseFluid< BASE >::resizeFields( localIndex const size, localIndex const numPts )
+{
+ integer const numPrimarySpecies = this->numPrimarySpecies();
+ integer const numSecondarySpecies = this->numSecondarySpecies();
+ integer const numKineticReactions = this->numKineticReactions();
+
+ m_initialPrimarySpeciesConcentration.resize( size, numPts, numPrimarySpecies );
+ m_secondarySpeciesConcentration.resize( size, numPts, numSecondarySpecies );
+ m_primarySpeciesAggregateConcentration.resize( size, numPts, numPrimarySpecies );
+ m_primarySpeciesAggregateConcentration_n.resize( size, numPts, numPrimarySpecies );
+ m_primarySpeciesMobileAggregateConcentration.resize( size, numPts, numPrimarySpecies );
+ m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations.resize( size, numPts, numPrimarySpecies, numPrimarySpecies );
+ m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations.resize( size, numPts, numPrimarySpecies, numPrimarySpecies );
+ m_kineticReactionRates.resize( size, numPts, numKineticReactions );
+ m_aggregateSpeciesRates.resize( size, numPts, numPrimarySpecies );
+ m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations.resize( size, numPts, numPrimarySpecies, numPrimarySpecies );
+}
+
+template< typename BASE >
+void ReactiveSinglePhaseFluid< BASE >::allocateConstitutiveData( dataRepository::Group & parent,
+ localIndex const numConstitutivePointsPerParentIndex )
+{
+ BASE::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex );
+ resizeFields( parent.size(), numConstitutivePointsPerParentIndex );
+}
+
+template class ReactiveSinglePhaseFluid< CompressibleSinglePhaseFluid >;
+
+REGISTER_CATALOG_ENTRY( ConstitutiveBase, ReactiveCompressibleSinglePhaseFluid, string const &, Group * const )
+
+template class ReactiveSinglePhaseFluid< ThermalCompressibleSinglePhaseFluid >;
+
+REGISTER_CATALOG_ENTRY( ConstitutiveBase, ReactiveThermalCompressibleSinglePhaseFluid, string const &, Group * const )
+
+} // namespace reactivefluid
+
+} // namespace constitutive
+
+} // namespace geos
diff --git a/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.hpp b/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.hpp
new file mode 100644
index 00000000000..6346d030c4f
--- /dev/null
+++ b/src/coreComponents/constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.hpp
@@ -0,0 +1,529 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ReactiveSinglePhaseFluid.hpp
+ */
+
+#ifndef GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVESINGLEPHASEFLUID_HPP_
+#define GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVESINGLEPHASEFLUID_HPP_
+
+#include "common/format/EnumStrings.hpp"
+
+#include "constitutive/ConstitutiveBase.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp"
+#include "constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.hpp"
+#include "constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.hpp"
+
+#include "constitutive/HPCReact/src/reactions/geochemistry/GeochemicalSystems.hpp"
+#include "constitutive/HPCReact/src/reactions/exampleSystems/BulkGeneric.hpp"
+#include "constitutive/HPCReact/src/reactions/exampleSystems/ChainGeneric.hpp"
+#include "constitutive/HPCReact/src/reactions/exampleSystems/MoMasBenchmark.hpp"
+#include "constitutive/HPCReact/src/reactions/reactionsSystems/EquilibriumReactions.hpp"
+#include "constitutive/HPCReact/src/reactions/reactionsSystems/MixedEquilibriumKineticReactions.hpp"
+#include "constitutive/HPCReact/src/reactions/massActions/MassActions.hpp"
+#include
+
+namespace geos
+{
+
+namespace constitutive
+{
+
+namespace reactivefluid
+{
+
+using namespace hpcReact::reactionsSystems;
+
+enum class ChemicalSystemType : integer
+{
+ carbonate,
+ carbonateAllEquilibrium,
+ ultramafic,
+ momasEasy,
+ momasMedium,
+ chainSerialAllKinetic
+};
+
+template< typename BASE >
+class ReactiveSinglePhaseFluid : public BASE
+{
+public:
+
+ ReactiveSinglePhaseFluid( string const & name,
+ dataRepository::Group * const parent );
+
+ virtual std::unique_ptr< ConstitutiveBase >
+ deliverClone( string const & name,
+ dataRepository::Group * const parent ) const override;
+
+ static string catalogName() { return string( "Reactive" ) + BASE::catalogName(); }
+ virtual string getCatalogName() const override { return catalogName(); }
+
+ virtual void saveConvergedState() const override;
+
+ virtual void allocateConstitutiveData( dataRepository::Group & parent,
+ localIndex const numConstitutivePointsPerParentIndex ) override;
+
+ static constexpr integer MAX_NUM_SPECIES = 20;
+ static constexpr integer MAX_NUM_KINETIC_REACTIONS = 10;
+
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > primarySpeciesAggregateConcentration() const
+ { return m_primarySpeciesAggregateConcentration; }
+
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > primarySpeciesAggregateConcentration_n() const
+ { return m_primarySpeciesAggregateConcentration_n; }
+
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > primarySpeciesMobileAggregateConcentration() const
+ { return m_primarySpeciesMobileAggregateConcentration; }
+
+ arrayView4d< real64 const, reactivefluid::USD_SPECIES_DC > dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations() const
+ { return m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations; }
+
+ arrayView4d< real64 const, reactivefluid::USD_SPECIES_DC > dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations() const
+ { return m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations; }
+
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > secondarySpeciesConcentration() const
+ { return m_secondarySpeciesConcentration; }
+
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > aggregateSpeciesRates() const
+ { return m_aggregateSpeciesRates; }
+
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > kineticReactionRates() const
+ { return m_kineticReactionRates; }
+
+ arrayView4d< real64 const, reactivefluid::USD_SPECIES_DC > dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations() const
+ { return m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations; }
+
+ integer numPrimarySpecies() const { return m_numPrimarySpecies; }
+
+ integer numSecondarySpecies() const { return m_numSecondarySpecies; }
+
+ integer numKineticReactions() const { return m_numKineticReactions; }
+
+ /**
+ * @brief Kernel wrapper class for ReactiveSinglePhaseFluid.
+ */
+ template< typename REACTION_PARAMS_TYPE >
+ class ReactionKernelWrapper
+ {
+
+public:
+
+ ReactionKernelWrapper( arrayView3d< real64, reactivefluid::USD_SPECIES > const & primarySpeciesAggregateConcentration,
+ arrayView3d< real64, reactivefluid::USD_SPECIES > const & primarySpeciesMobileAggregateConcentration,
+ arrayView4d< real64, reactivefluid::USD_SPECIES_DC > const & dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ arrayView4d< real64, reactivefluid::USD_SPECIES_DC > const & dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const & initialPrimarySpeciesConcentration,
+ arrayView3d< real64, reactivefluid::USD_SPECIES > const & secondarySpeciesConcentration,
+ arrayView3d< real64, reactivefluid::USD_SPECIES > const & kineticReactionRates,
+ arrayView3d< real64, reactivefluid::USD_SPECIES > const & aggregateSpeciesRates,
+ arrayView4d< real64, reactivefluid::USD_SPECIES_DC > const & dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations,
+ integer const numPrimarySpecies,
+ integer const numSecondarySpecies,
+ integer const numKineticReactions,
+ REACTION_PARAMS_TYPE params ):
+ m_numPrimarySpecies( numPrimarySpecies ),
+ m_numSecondarySpecies( numSecondarySpecies ),
+ m_numKineticReactions( numKineticReactions ),
+ m_primarySpeciesAggregateConcentration( primarySpeciesAggregateConcentration ),
+ m_primarySpeciesMobileAggregateConcentration( primarySpeciesMobileAggregateConcentration ),
+ m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations( dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations ),
+ m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations( dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations ),
+ m_initialPrimarySpeciesConcentration( initialPrimarySpeciesConcentration ),
+ m_secondarySpeciesConcentration( secondarySpeciesConcentration ),
+ m_kineticReactionRates( kineticReactionRates ),
+ m_aggregateSpeciesRates( aggregateSpeciesRates ),
+ m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations( dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations ),
+ m_params( params )
+ {}
+
+ using EquilibriumReactionsType = hpcReact::reactionsSystems::EquilibriumReactions< real64, integer, localIndex >;
+
+ /**
+ * @brief Get number of elements in this wrapper.
+ * @return number of elements
+ */
+ GEOS_HOST_DEVICE
+ localIndex numElems() const { return m_secondarySpeciesConcentration.size( 0 ); }
+
+ GEOS_HOST_DEVICE
+ void updateEquilibriumReaction( localIndex const k,
+ real64 const pressure,
+ real64 const temperature,
+ arraySlice1d< real64, compflow::USD_COMP - 1 > const & logPrimarySpeciesConcentration ) const;
+
+ GEOS_HOST_DEVICE
+ void enforceEquilibrium( real64 const pressure,
+ real64 const temperature,
+ arraySlice1d< real64 const, reactivefluid::USD_SPECIES - 2 > const & targetPrimarySpeciesAggregateConcentration,
+ arraySlice1d< real64 const, reactivefluid::USD_SPECIES - 2 > const & initialPrimarySpeciesConcentration,
+ arraySlice1d< real64, compflow::USD_COMP - 1 > const & logPrimarySpeciesConcentration,
+ arraySlice1d< real64 > const & logSecondarySpeciesConcentration ) const;
+
+ GEOS_HOST_DEVICE
+ void updateMixedReactionSystem( localIndex const k,
+ real64 const pressure,
+ real64 const temperature,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & logPrimarySpeciesConcentration,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & surfaceArea ) const;
+
+ GEOS_HOST_DEVICE
+ void computeAggregateConcentrationsAndRates( real64 const pressure,
+ real64 const temperature,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & logPrimarySpeciesConcentration,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & surfaceArea,
+ arraySlice1d< real64 > const & logSecondarySpeciesConcentration,
+ arraySlice1d< real64, reactivefluid::USD_SPECIES - 2 > const & primarySpeciesAggregateConcentration,
+ arraySlice1d< real64, reactivefluid::USD_SPECIES - 2 > const & primarySpeciesMobileAggregateConcentration,
+ arraySlice2d< real64, reactivefluid::USD_SPECIES_DC - 2 > const & dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ arraySlice2d< real64, reactivefluid::USD_SPECIES_DC - 2 > const & dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ arraySlice1d< real64, reactivefluid::USD_SPECIES - 2 > const & reactionRates,
+ arraySlice2d< real64 > const & dReactionRates_dLogPrimarySpeciesConcentrations,
+ arraySlice1d< real64, reactivefluid::USD_SPECIES - 2 > const & aggregateSpeciesRates,
+ arraySlice2d< real64, reactivefluid::USD_SPECIES_DC - 2 > const & dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations ) const;
+
+protected:
+
+ integer m_numPrimarySpecies;
+
+ integer m_numSecondarySpecies;
+
+ integer m_numKineticReactions;
+
+ arrayView3d< real64, reactivefluid::USD_SPECIES > m_primarySpeciesAggregateConcentration;
+
+ arrayView3d< real64, reactivefluid::USD_SPECIES > m_primarySpeciesMobileAggregateConcentration;
+
+ arrayView4d< real64, reactivefluid::USD_SPECIES_DC > m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations;
+
+ arrayView4d< real64, reactivefluid::USD_SPECIES_DC > m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations;
+
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const m_initialPrimarySpeciesConcentration;
+
+ arrayView3d< real64, reactivefluid::USD_SPECIES > m_secondarySpeciesConcentration;
+
+ arrayView3d< real64, reactivefluid::USD_SPECIES > m_kineticReactionRates;
+
+ arrayView3d< real64, reactivefluid::USD_SPECIES > m_aggregateSpeciesRates;
+
+ arrayView4d< real64, reactivefluid::USD_SPECIES_DC > m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations;
+
+ REACTION_PARAMS_TYPE m_params;
+ };
+
+ std::variant<
+ typename ReactiveSinglePhaseFluid< BASE >::template ReactionKernelWrapper< hpcReact::geochemistry::ultramaficSystemType >,
+ typename ReactiveSinglePhaseFluid< BASE >::template ReactionKernelWrapper< hpcReact::geochemistry::carbonateSystemType >,
+ typename ReactiveSinglePhaseFluid< BASE >::template ReactionKernelWrapper< hpcReact::geochemistry::carbonateSystemAllEquilibriumType >,
+ typename ReactiveSinglePhaseFluid< BASE >::template ReactionKernelWrapper< hpcReact::ChainGeneric::serialAllKineticType >,
+ typename ReactiveSinglePhaseFluid< BASE >::template ReactionKernelWrapper< hpcReact::MoMasBenchmark::mediumCaseType >,
+ typename ReactiveSinglePhaseFluid< BASE >::template ReactionKernelWrapper< hpcReact::MoMasBenchmark::easyCaseType > >
+ createReactionKernelWrapper() const
+ {
+ using namespace hpcReact::geochemistry;
+ using namespace hpcReact::MoMasBenchmark;
+ using namespace hpcReact::bulkGeneric;
+ using namespace hpcReact::ChainGeneric;
+ switch( m_chemicalSystemType )
+ {
+ case ChemicalSystemType::ultramafic:
+ return ReactionKernelWrapper< ultramaficSystemType >( m_primarySpeciesAggregateConcentration,
+ m_primarySpeciesMobileAggregateConcentration,
+ m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_initialPrimarySpeciesConcentration,
+ m_secondarySpeciesConcentration,
+ m_kineticReactionRates,
+ m_aggregateSpeciesRates,
+ m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations,
+ m_numPrimarySpecies,
+ m_numSecondarySpecies,
+ m_numKineticReactions,
+ ultramaficSystem );
+
+ case ChemicalSystemType::carbonate:
+ return ReactionKernelWrapper< carbonateSystemType >( m_primarySpeciesAggregateConcentration,
+ m_primarySpeciesMobileAggregateConcentration,
+ m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_initialPrimarySpeciesConcentration,
+ m_secondarySpeciesConcentration,
+ m_kineticReactionRates,
+ m_aggregateSpeciesRates,
+ m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations,
+ m_numPrimarySpecies,
+ m_numSecondarySpecies,
+ m_numKineticReactions,
+ carbonateSystem );
+ case ChemicalSystemType::carbonateAllEquilibrium:
+ return ReactionKernelWrapper< carbonateSystemAllEquilibriumType >( m_primarySpeciesAggregateConcentration,
+ m_primarySpeciesMobileAggregateConcentration,
+ m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_initialPrimarySpeciesConcentration,
+ m_secondarySpeciesConcentration,
+ m_kineticReactionRates,
+ m_aggregateSpeciesRates,
+ m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations,
+ m_numPrimarySpecies,
+ m_numSecondarySpecies,
+ m_numKineticReactions,
+ carbonateSystemAllEquilibrium );
+ case ChemicalSystemType::chainSerialAllKinetic:
+ return ReactionKernelWrapper< serialAllKineticType >( m_primarySpeciesAggregateConcentration,
+ m_primarySpeciesMobileAggregateConcentration,
+ m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_initialPrimarySpeciesConcentration,
+ m_secondarySpeciesConcentration,
+ m_kineticReactionRates,
+ m_aggregateSpeciesRates,
+ m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations,
+ m_numPrimarySpecies,
+ m_numSecondarySpecies,
+ m_numKineticReactions,
+ serialAllKineticParams );
+ case ChemicalSystemType::momasMedium:
+ return ReactionKernelWrapper< mediumCaseType >( m_primarySpeciesAggregateConcentration,
+ m_primarySpeciesMobileAggregateConcentration,
+ m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_initialPrimarySpeciesConcentration,
+ m_secondarySpeciesConcentration,
+ m_kineticReactionRates,
+ m_aggregateSpeciesRates,
+ m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations,
+ m_numPrimarySpecies,
+ m_numSecondarySpecies,
+ m_numKineticReactions,
+ mediumCaseParams );
+ default:
+ return ReactionKernelWrapper< easyCaseType >( m_primarySpeciesAggregateConcentration,
+ m_primarySpeciesMobileAggregateConcentration,
+ m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ m_initialPrimarySpeciesConcentration,
+ m_secondarySpeciesConcentration,
+ m_kineticReactionRates,
+ m_aggregateSpeciesRates,
+ m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations,
+ m_numPrimarySpecies,
+ m_numSecondarySpecies,
+ m_numKineticReactions,
+ easyCaseParams );
+ }
+ }
+
+ struct viewKeyStruct : ConstitutiveBase::viewKeyStruct
+ {
+ static constexpr char const * chemicalSystemNameString() { return "chemicalSystemType"; }
+ };
+
+protected:
+
+ virtual void postInputInitialization() override;
+
+ virtual void resizeFields( localIndex const size, localIndex const numPts );
+
+ integer m_numPrimarySpecies;
+
+ integer m_numSecondarySpecies;
+
+ integer m_numKineticReactions;
+
+ array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES > m_initialPrimarySpeciesConcentration;
+
+ array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES > m_secondarySpeciesConcentration;
+
+ array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES > m_primarySpeciesAggregateConcentration;
+
+ array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES > m_primarySpeciesAggregateConcentration_n;
+
+ array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES > m_primarySpeciesMobileAggregateConcentration;
+
+ array4d< real64, constitutive::reactivefluid::LAYOUT_SPECIES_DC > m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations;
+
+ array4d< real64, constitutive::reactivefluid::LAYOUT_SPECIES_DC > m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations;
+
+ array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES > m_kineticReactionRates;
+
+ array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES > m_aggregateSpeciesRates;
+
+ array4d< real64, constitutive::reactivefluid::LAYOUT_SPECIES_DC > m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations;
+
+ ChemicalSystemType m_chemicalSystemType;
+};
+
+// these aliases are useful in constitutive dispatch
+using ReactiveCompressibleSinglePhaseFluid = ReactiveSinglePhaseFluid< CompressibleSinglePhaseFluid >;
+
+using ReactiveThermalCompressibleSinglePhaseFluid = ReactiveSinglePhaseFluid< ThermalCompressibleSinglePhaseFluid >;
+
+template< typename BASE >
+template< typename REACTION_PARAMS_TYPE >
+GEOS_HOST_DEVICE
+inline void
+ReactiveSinglePhaseFluid< BASE >::ReactionKernelWrapper< REACTION_PARAMS_TYPE >::
+updateEquilibriumReaction( localIndex const k,
+ real64 const pressure,
+ real64 const temperature,
+ arraySlice1d< real64, compflow::USD_COMP - 1 > const & logPrimarySpeciesConcentration ) const
+{
+ integer const numSecondarySpecies = m_numSecondarySpecies;
+
+ if( numSecondarySpecies > 0 )
+ {
+ stackArray1d< real64, MAX_NUM_SPECIES > logSecondarySpeciesConcentration( numSecondarySpecies );
+
+ enforceEquilibrium( pressure, temperature, m_primarySpeciesAggregateConcentration[k][0], m_initialPrimarySpeciesConcentration[k][0], logPrimarySpeciesConcentration,
+ logSecondarySpeciesConcentration.toSlice() );
+
+ for( integer i=0; i < numSecondarySpecies; ++i )
+ {
+ m_secondarySpeciesConcentration[k][0][i] = LvArray::math::exp( logSecondarySpeciesConcentration[i] );
+ }
+ }
+ else
+ {
+ GEOS_UNUSED_VAR( k, pressure, temperature, logPrimarySpeciesConcentration );
+ }
+
+}
+
+template< typename BASE >
+template< typename REACTION_PARAMS_TYPE >
+GEOS_HOST_DEVICE
+inline void
+ReactiveSinglePhaseFluid< BASE >::ReactionKernelWrapper< REACTION_PARAMS_TYPE >::
+enforceEquilibrium( real64 const pressure,
+ real64 const temperature,
+ arraySlice1d< real64 const, reactivefluid::USD_SPECIES - 2 > const & targetPrimarySpeciesAggregateConcentration,
+ arraySlice1d< real64 const, reactivefluid::USD_SPECIES - 2 > const & initialPrimarySpeciesConcentration,
+ arraySlice1d< real64, compflow::USD_COMP - 1 > const & logPrimarySpeciesConcentration,
+ arraySlice1d< real64 > const & logSecondarySpeciesConcentration ) const
+{
+ GEOS_UNUSED_VAR( pressure );
+
+ integer const numPrimarySpecies = m_numPrimarySpecies;
+
+ stackArray1d< real64, MAX_NUM_SPECIES > logPrimarySpeciesConcentration0( numPrimarySpecies );
+ stackArray1d< real64, MAX_NUM_SPECIES > targetPrimarySpeciesAggregateConc( numPrimarySpecies );
+
+ for( integer i=0; i < numPrimarySpecies; ++i )
+ {
+ targetPrimarySpeciesAggregateConc[i] = targetPrimarySpeciesAggregateConcentration[i];
+ logPrimarySpeciesConcentration0[i] = LvArray::math::log( initialPrimarySpeciesConcentration[i] );
+ }
+
+ // 1. We enforce equilibrium
+ EquilibriumReactionsType::enforceEquilibrium_Aggregate( temperature, m_params, targetPrimarySpeciesAggregateConc, logPrimarySpeciesConcentration0, logPrimarySpeciesConcentration );
+
+ // 2. We calculate the secondary species concentration
+ hpcReact::massActions::calculateLogSecondarySpeciesConcentration< real64,
+ localIndex,
+ localIndex >( m_params, logPrimarySpeciesConcentration, logSecondarySpeciesConcentration );
+}
+
+template< typename BASE >
+template< typename REACTION_PARAMS_TYPE >
+GEOS_HOST_DEVICE
+inline void
+ReactiveSinglePhaseFluid< BASE >::ReactionKernelWrapper< REACTION_PARAMS_TYPE >::
+updateMixedReactionSystem( localIndex const k,
+ real64 const pressure,
+ real64 const temperature,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & logPrimarySpeciesConcentration,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & surfaceArea ) const
+{
+ integer const numPrimarySpecies = m_numPrimarySpecies;
+ integer const numSecondarySpecies = m_numSecondarySpecies;
+ integer const numKineticReactions = m_numKineticReactions;
+
+ stackArray1d< real64, MAX_NUM_SPECIES > logSecondarySpeciesConcentration( numSecondarySpecies );
+ stackArray2d< real64, MAX_NUM_KINETIC_REACTIONS * MAX_NUM_SPECIES > dReactionRates_dLogPrimarySpeciesConcentrations( numKineticReactions, numPrimarySpecies );
+
+ computeAggregateConcentrationsAndRates( pressure,
+ temperature,
+ logPrimarySpeciesConcentration,
+ surfaceArea,
+ logSecondarySpeciesConcentration.toSlice(),
+ m_primarySpeciesAggregateConcentration[k][0],
+ m_primarySpeciesMobileAggregateConcentration[k][0],
+ m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations[k][0],
+ m_dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations[k][0],
+ m_kineticReactionRates[k][0],
+ dReactionRates_dLogPrimarySpeciesConcentrations.toSlice(),
+ m_aggregateSpeciesRates[k][0],
+ m_dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations[k][0] );
+
+ for( integer i=0; i < numSecondarySpecies; ++i )
+ {
+ m_secondarySpeciesConcentration[k][0][i] = LvArray::math::exp( logSecondarySpeciesConcentration[i] );
+ }
+}
+
+template< typename BASE >
+template< typename REACTION_PARAMS_TYPE >
+GEOS_HOST_DEVICE
+inline void
+ReactiveSinglePhaseFluid< BASE >::ReactionKernelWrapper< REACTION_PARAMS_TYPE >::
+computeAggregateConcentrationsAndRates( real64 const pressure,
+ real64 const temperature,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & logPrimarySpeciesConcentration,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & surfaceArea,
+ arraySlice1d< real64 > const & logSecondarySpeciesConcentration,
+ arraySlice1d< real64, reactivefluid::USD_SPECIES - 2 > const & primarySpeciesAggregateConcentration,
+ arraySlice1d< real64, reactivefluid::USD_SPECIES - 2 > const & primarySpeciesMobileAggregateConcentration,
+ arraySlice2d< real64, reactivefluid::USD_SPECIES_DC - 2 > const & dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ arraySlice2d< real64, reactivefluid::USD_SPECIES_DC - 2 > const & dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ arraySlice1d< real64, reactivefluid::USD_SPECIES - 2 > const & reactionRates,
+ arraySlice2d< real64 > const & dReactionRates_dLogPrimarySpeciesConcentrations,
+ arraySlice1d< real64, reactivefluid::USD_SPECIES - 2 > const & aggregateSpeciesRates,
+ arraySlice2d< real64, reactivefluid::USD_SPECIES_DC - 2 > const & dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations ) const
+{
+ GEOS_UNUSED_VAR( pressure );
+
+ MixedEquilibriumKineticReactions< real64, localIndex, localIndex, true >::
+ updateMixedSystem( temperature,
+ m_params,
+ logPrimarySpeciesConcentration,
+ surfaceArea,
+ logSecondarySpeciesConcentration,
+ primarySpeciesAggregateConcentration,
+ primarySpeciesMobileAggregateConcentration,
+ dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ reactionRates,
+ dReactionRates_dLogPrimarySpeciesConcentrations,
+ aggregateSpeciesRates,
+ dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations );
+}
+
+ENUM_STRINGS( ChemicalSystemType,
+ "carbonate",
+ "carbonateAllEquilibrium",
+ "ultramafic",
+ "momasEasy",
+ "momasMedium",
+ "chainSerialAllKinetic" );
+
+} // namespace reactivefluid
+
+} // namespace constitutive
+
+} // namespace geos
+
+#endif // GEOS_CONSTITUTIVE_FLUID_REACTIVEFLUID_REACTIVESINGLEPHASEFLUID_HPP_
diff --git a/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.hpp b/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.hpp
index 09faa09ab49..e177053795c 100644
--- a/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.hpp
+++ b/src/coreComponents/constitutive/fluid/singlefluid/CompressibleSinglePhaseFluid.hpp
@@ -130,6 +130,21 @@ class CompressibleSinglePhaseUpdate : public SingleFluidBaseUpdate
m_dViscosity[k][q][DerivOffset::dP] );
}
+ GEOS_HOST_DEVICE
+ GEOS_FORCE_INLINE
+ virtual void update( localIndex const k,
+ localIndex const q,
+ real64 const pressure,
+ real64 const GEOS_UNUSED_PARAM( temperature ),
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & GEOS_UNUSED_PARAM( logPrimaryConcentration ) ) const override
+ {
+ compute( pressure,
+ m_density[k][q],
+ m_dDensity[k][q][DerivOffset::dP],
+ m_viscosity[k][q],
+ m_dViscosity[k][q][DerivOffset::dP] );
+ }
+
private:
/// Relationship between the fluid density and pressure
diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp
index 57baebcd702..87e5866e79d 100644
--- a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp
+++ b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp
@@ -20,6 +20,7 @@
#ifndef GEOS_CONSTITUTIVE_FLUID_SINGLEFLUID_SINGLEFLUIDBASE_HPP
#define GEOS_CONSTITUTIVE_FLUID_SINGLEFLUID_SINGLEFLUIDBASE_HPP
+#include "common/DataLayouts.hpp"
#include "constitutive/ConstitutiveBase.hpp"
#include "constitutive/fluid/singlefluid/SingleFluidLayouts.hpp"
#include "constitutive/fluid/singlefluid/SingleFluidUtils.hpp"
@@ -240,6 +241,21 @@ class SingleFluidBaseUpdate
real64 const pressure,
real64 const temperature ) const = 0;
+ /**
+ * @brief Update fluid state at a single point.
+ * @param[in] k element index
+ * @param[in] q gauss point index
+ * @param[in] pressure the target pressure value
+ * @param[in] temperature the target temperature value
+ * @param[in] logPrimaryConcentration the target logPrimaryConc value
+ */
+ GEOS_HOST_DEVICE
+ virtual void update( localIndex const k,
+ localIndex const q,
+ real64 const pressure,
+ real64 const temperature,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & logPrimaryConcentration ) const = 0;
+
};
//END_SPHINX_INCLUDE_02
diff --git a/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.hpp b/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.hpp
index 574164785b7..2f110c295ef 100644
--- a/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.hpp
+++ b/src/coreComponents/constitutive/fluid/singlefluid/ThermalCompressibleSinglePhaseFluid.hpp
@@ -165,6 +165,30 @@ class ThermalCompressibleSinglePhaseUpdate : public SingleFluidBaseUpdate
m_dEnthalpy[k][q][DerivOffset::dT] );
}
+ GEOS_HOST_DEVICE
+ GEOS_FORCE_INLINE
+ virtual void update( localIndex const k,
+ localIndex const q,
+ real64 const pressure,
+ real64 const temperature,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & GEOS_UNUSED_PARAM( logPrimaryConcentration ) ) const override
+ {
+ compute( pressure,
+ temperature,
+ m_density[k][q],
+ m_dDensity[k][q][DerivOffset::dP],
+ m_dDensity[k][q][DerivOffset::dT],
+ m_viscosity[k][q],
+ m_dViscosity[k][q][DerivOffset::dP],
+ m_dViscosity[k][q][DerivOffset::dT],
+ m_internalEnergy[k][q],
+ m_dInternalEnergy[k][q][DerivOffset::dP],
+ m_dInternalEnergy[k][q][DerivOffset::dT],
+ m_enthalpy[k][q],
+ m_dEnthalpy[k][q][DerivOffset::dP],
+ m_dEnthalpy[k][q][DerivOffset::dT] );
+ }
+
private:
/// Fluid internal energy and derivatives
diff --git a/src/coreComponents/constitutive/solid/CoupledSolid.hpp b/src/coreComponents/constitutive/solid/CoupledSolid.hpp
index 93e26caa84a..244c899fee7 100644
--- a/src/coreComponents/constitutive/solid/CoupledSolid.hpp
+++ b/src/coreComponents/constitutive/solid/CoupledSolid.hpp
@@ -22,6 +22,7 @@
#define GEOS_CONSTITUTIVE_SOLID_COUPLEDSOLID_HPP_
#include "constitutive/solid/CoupledSolidBase.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp"
namespace geos
{
@@ -105,6 +106,25 @@ class CoupledSolidUpdates
temperature, temperature_k, temperature_n );
}
+ GEOS_HOST_DEVICE
+ virtual void updateStateFromPressureTemperatureAndReactions( localIndex const k,
+ localIndex const q,
+ real64 const & pressure,
+ real64 const & temperature,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & kineticReactionMolarIncrements ) const
+ {
+ GEOS_UNUSED_VAR( k, q, pressure, temperature, kineticReactionMolarIncrements );
+ }
+
+ GEOS_HOST_DEVICE
+ virtual void updateSurfaceArea( localIndex const k,
+ localIndex const q,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & initialSurfaceArea,
+ arraySlice1d< real64, compflow::USD_COMP - 1 > const & surfaceArea ) const
+ {
+ GEOS_UNUSED_VAR( k, q, initialSurfaceArea, surfaceArea );
+ }
+
GEOS_HOST_DEVICE
virtual real64 getShearModulus( localIndex const k ) const
{
diff --git a/src/coreComponents/constitutive/solid/PorousReactiveSolid.cpp b/src/coreComponents/constitutive/solid/PorousReactiveSolid.cpp
new file mode 100644
index 00000000000..fb36db2a959
--- /dev/null
+++ b/src/coreComponents/constitutive/solid/PorousReactiveSolid.cpp
@@ -0,0 +1,57 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 PorousReactiveSolid.cpp
+ */
+
+#include "PorousReactiveSolid.hpp"
+#include "ElasticIsotropic.hpp"
+#include "constitutive/permeability/ConstantPermeability.hpp"
+#include "constitutive/permeability/CarmanKozenyPermeability.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+namespace constitutive
+{
+
+template< typename SOLID_TYPE,
+ typename PERM_TYPE >
+PorousReactiveSolid< SOLID_TYPE, PERM_TYPE >::PorousReactiveSolid( string const & name, Group * const parent ):
+ CoupledSolid< SOLID_TYPE, ReactivePorosity, PERM_TYPE >( name, parent )
+{}
+
+template< typename SOLID_TYPE,
+ typename PERM_TYPE >
+void PorousReactiveSolid< SOLID_TYPE, PERM_TYPE >::initializeState() const
+{
+ CoupledSolid< SOLID_TYPE, ReactivePorosity, PERM_TYPE >::initializeState();
+}
+
+// Register all PorousReactiveSolid model types.
+typedef PorousReactiveSolid< ElasticIsotropic, ConstantPermeability > PorousReactiveElasticIsotropicConstant;
+typedef PorousReactiveSolid< ElasticIsotropic, CarmanKozenyPermeability > PorousReactiveElasticIsotropicCK;
+
+
+REGISTER_CATALOG_ENTRY( ConstitutiveBase, PorousReactiveElasticIsotropicConstant, string const &, Group * const )
+REGISTER_CATALOG_ENTRY( ConstitutiveBase, PorousReactiveElasticIsotropicCK, string const &, Group * const )
+
+
+}
+} /* namespace geos */
diff --git a/src/coreComponents/constitutive/solid/PorousReactiveSolid.hpp b/src/coreComponents/constitutive/solid/PorousReactiveSolid.hpp
new file mode 100644
index 00000000000..ccebb893ea3
--- /dev/null
+++ b/src/coreComponents/constitutive/solid/PorousReactiveSolid.hpp
@@ -0,0 +1,315 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 PorousReactiveSolid.hpp
+ */
+
+#ifndef GEOS_CONSTITUTIVE_SOLID_POROUSREACTIVESOLID_HPP_
+#define GEOS_CONSTITUTIVE_SOLID_POROUSREACTIVESOLID_HPP_
+
+#include "constitutive/solid/CoupledSolid.hpp"
+#include "constitutive/solid/porosity/ReactivePorosity.hpp"
+#include "constitutive/solid/SolidBase.hpp"
+#include "constitutive/permeability/ConstantPermeability.hpp"
+
+#include "constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp"
+
+namespace geos
+{
+namespace constitutive
+{
+
+/**
+ * @brief Provides kernel-callable constitutive update routines
+ *
+ *
+ * @tparam SOLID_TYPE type of the porosity model
+ */
+template< typename SOLID_TYPE,
+ typename PERM_TYPE >
+class PorousReactiveSolidUpdates : public CoupledSolidUpdates< SOLID_TYPE, ReactivePorosity, PERM_TYPE >
+{
+public:
+
+ using DiscretizationOps = typename SOLID_TYPE::KernelWrapper::DiscretizationOps;
+
+ /**
+ * @brief Constructor
+ */
+ PorousReactiveSolidUpdates( SOLID_TYPE const & solidModel,
+ ReactivePorosity const & porosityModel,
+ PERM_TYPE const & permModel ):
+ CoupledSolidUpdates< SOLID_TYPE, ReactivePorosity, PERM_TYPE >( solidModel, porosityModel, permModel )
+ {}
+
+ GEOS_HOST_DEVICE
+ virtual void updateStateFromPressureTemperatureAndReactions( localIndex const k,
+ localIndex const q,
+ real64 const & pressure,
+ real64 const & temperature,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & kineticReactionMolarIncrements ) const override final
+ {
+ GEOS_UNUSED_VAR( temperature );
+
+ m_porosityUpdate.updateFromReactions( k, q, kineticReactionMolarIncrements );
+ real64 const porosity = m_porosityUpdate.getPorosity( k, q );
+ m_permUpdate.updateFromPressureAndPorosity( k, q, pressure, porosity );
+ }
+
+ GEOS_HOST_DEVICE
+ virtual void updateSurfaceArea( localIndex const k,
+ localIndex const q,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & initialSurfaceArea,
+ arraySlice1d< real64, compflow::USD_COMP - 1 > const & surfaceArea ) const override final
+ {
+ real64 const porosity = m_porosityUpdate.getPorosity( k, q );
+ real64 const initialPorosity = m_porosityUpdate.getInitialPorosity( k, q );
+
+ for( integer r=0; r < initialSurfaceArea.size(); ++r )
+ {
+ real64 const volumeFraction_r = m_porosityUpdate.getVolumeFractionForMineral( k, q, r );
+ real64 const initialVolumeFraction_r = m_porosityUpdate.getInitialVolumeFractionForMineral( k, q, r );
+ surfaceArea[r] = initialSurfaceArea[r] * pow( volumeFraction_r / initialVolumeFraction_r, 2.0/3.0 )
+ * pow( porosity / initialPorosity, 2.0/3.0 );
+ }
+ }
+
+ GEOS_HOST_DEVICE
+ void smallStrainUpdateExplicitChemoMechanics( localIndex const k,
+ localIndex const q,
+ real64 const & timeIncrement,
+ real64 const & pressure,
+ real64 const & pressure_n,
+ real64 const & temperature,
+ real64 const & temperature_n,
+ real64 const & referenceTemperature,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > mineralReactionMolarIncrements,
+ real64 const ( &strainIncrement )[6],
+ real64 ( & totalStress )[6],
+ DiscretizationOps & stiffness ) const
+ {
+ GEOS_UNUSED_VAR( pressure_n, referenceTemperature );
+
+ real64 anelasticStrainIncrement = 0.0;
+
+ for( integer r=0; r < mineralReactionMolarIncrements.size(); ++r )
+ {
+ real64 const molarWeight = m_porosityUpdate.getMolarWeights( r );
+ real64 const mineralDensity = m_porosityUpdate.getMineralDensities( r );
+
+ anelasticStrainIncrement -= mineralReactionMolarIncrements[r] * molarWeight/mineralDensity;
+
+ // std::cout << "mineralReactionMolarIncrements[" << r << "] = " << mineralReactionMolarIncrements[r] << std::endl
+ // << "molarWeight[" << r << "] = " << molarWeight << std::endl
+ // << "mineralDensity[" << r << "] = " << mineralDensity << std::endl;
+ }
+
+ // Compute total stress increment and its derivative
+ real64 const deltaTemperatureFromLastStep = temperature - temperature_n;
+ computeTotalStress( k,
+ q,
+ timeIncrement,
+ pressure,
+ deltaTemperatureFromLastStep,
+ anelasticStrainIncrement,
+ strainIncrement,
+ totalStress,
+ stiffness );
+ }
+
+ /**
+ * @brief Return the stiffness at a given element (small-strain interface)
+ *
+ * @note If the material model has a strain-dependent material stiffness (e.g.
+ * any plasticity, damage, or nonlinear elastic model) then this interface will
+ * not work. Users should instead use one of the interfaces where a strain
+ * tensor is provided as input.
+ *
+ * @param k the element number
+ * @param stiffness the stiffness array
+ */
+ GEOS_HOST_DEVICE
+ inline
+ void getElasticStiffness( localIndex const k, localIndex const q, real64 ( & stiffness )[6][6] ) const
+ {
+ m_solidUpdate.getElasticStiffness( k, q, stiffness );
+ }
+
+ /**
+ * @brief Return the stiffness at a given element (small-strain interface)
+ *
+ * @param [in] k the element number
+ * @param [out] thermalExpansionCoefficient the thermal expansion coefficient
+ */
+ GEOS_HOST_DEVICE
+ inline
+ void getThermalExpansionCoefficient( localIndex const k, real64 & thermalExpansionCoefficient ) const
+ {
+ thermalExpansionCoefficient = m_solidUpdate.getThermalExpansionCoefficient( k );
+ }
+
+private:
+
+ using CoupledSolidUpdates< SOLID_TYPE, ReactivePorosity, PERM_TYPE >::m_solidUpdate;
+ using CoupledSolidUpdates< SOLID_TYPE, ReactivePorosity, PERM_TYPE >::m_porosityUpdate;
+ using CoupledSolidUpdates< SOLID_TYPE, ReactivePorosity, PERM_TYPE >::m_permUpdate;
+
+ GEOS_HOST_DEVICE
+ inline
+ void computeTotalStress( localIndex const k,
+ localIndex const q,
+ real64 const & timeIncrement,
+ real64 const & pressure,
+ real64 const & deltaTemperatureFromLastStep,
+ real64 const & anelasticStrainIncrement,
+ real64 const ( &strainIncrement )[6],
+ real64 ( & totalStress )[6],
+ DiscretizationOps & stiffness ) const
+ {
+ real64 const thermalExpansionCoefficient = m_solidUpdate.getThermalExpansionCoefficient( k );
+
+ // std::cout << "anelasticStrainIncrement = " << anelasticStrainIncrement << std::endl;
+
+ real64 mechanicsStrainIncrement[6]{};
+ mechanicsStrainIncrement[0] = strainIncrement[0] - thermalExpansionCoefficient * deltaTemperatureFromLastStep - anelasticStrainIncrement;
+ mechanicsStrainIncrement[1] = strainIncrement[1] - thermalExpansionCoefficient * deltaTemperatureFromLastStep - anelasticStrainIncrement;
+ mechanicsStrainIncrement[2] = strainIncrement[2] - thermalExpansionCoefficient * deltaTemperatureFromLastStep - anelasticStrainIncrement;
+ mechanicsStrainIncrement[3] = strainIncrement[3];
+ mechanicsStrainIncrement[4] = strainIncrement[4];
+ mechanicsStrainIncrement[5] = strainIncrement[5];
+
+ // Compute total stress increment and its derivative w.r.t. pressure
+ m_solidUpdate.smallStrainUpdate( k,
+ q,
+ timeIncrement,
+ mechanicsStrainIncrement,
+ totalStress, // first effective stress increment accumulated
+ stiffness );
+
+ // Add the contributions of pressure to the total stress
+ LvArray::tensorOps::symAddIdentity< 3 >( totalStress, -pressure );
+
+ }
+
+};
+
+/**
+ * @brief PorousReactiveSolidBase class used for dispatch of all Porous solids.
+ */
+class PorousReactiveSolidBase
+{};
+
+/**
+ * @brief Class to represent a porous material for poromechanics simulations.
+ * It is used as an interface to access all constitutive models relative to the properties of a porous material.
+ *
+ * @tparam SOLID_TYPE type of solid model
+ */
+template< typename SOLID_TYPE,
+ typename PERM_TYPE >
+class PorousReactiveSolid : public CoupledSolid< SOLID_TYPE, ReactivePorosity, PERM_TYPE >
+{
+public:
+
+ /// Alias for ElasticIsotropicUpdates
+ using KernelWrapper = PorousReactiveSolidUpdates< SOLID_TYPE, PERM_TYPE >;
+
+ /**
+ * @brief Constructor
+ * @param name Object name
+ * @param parent Object's parent group
+ */
+ PorousReactiveSolid( string const & name, dataRepository::Group * const parent );
+
+ /**
+ * @brief Catalog name
+ * @return Static catalog string
+ */
+ static string catalogName()
+ {
+ if constexpr ( std::is_same_v< PERM_TYPE, ConstantPermeability > ) // default case
+ {
+ return string( "PorousReactive" ) + SOLID_TYPE::catalogName();
+ }
+ else // special cases
+ {
+ return string( "PorousReactive" ) + SOLID_TYPE::catalogName() + PERM_TYPE::catalogName();
+ }
+ }
+
+ /**
+ * @brief Get catalog name
+ * @return Catalog name string
+ */
+ virtual string getCatalogName() const override { return catalogName(); }
+
+ /**
+ * @brief Create a instantiation of the PorousReactiveSolidUpdates class
+ * that refers to the data in this.
+ * @return An instantiation of PorousReactiveSolidUpdates.
+ */
+ KernelWrapper createKernelUpdates() const
+ {
+ return KernelWrapper( getSolidModel(),
+ getPorosityModel(),
+ getPermModel() );
+ }
+
+ /**
+ * @brief initialize the constitutive models fields.
+ */
+ virtual void initializeState() const override final;
+
+ /**
+ * @brief Const/non-mutable accessor for density
+ * @return Accessor
+ */
+ arrayView2d< real64 const > const getDensity() const
+ {
+ return getSolidModel().getDensity();
+ }
+
+ /**
+ * @brief Const/non-mutable accessor for the mean stress increment at the previous sequential iteration
+ * @return Accessor
+ */
+ arrayView2d< real64 const > const getMeanStressIncrement_k() const
+ {
+ return getPorosityModel().getMeanStressIncrement_k();
+ }
+
+ /**
+ * @brief Non-const accessor for the mean stress increment at the previous sequential iteration
+ * @return Accessor
+ */
+ arrayView1d< real64 > const getAverageMeanStressIncrement_k()
+ {
+ return getPorosityModel().getAverageMeanStressIncrement_k();
+ }
+
+private:
+ using CoupledSolid< SOLID_TYPE, ReactivePorosity, PERM_TYPE >::getSolidModel;
+ using CoupledSolid< SOLID_TYPE, ReactivePorosity, PERM_TYPE >::getPorosityModel;
+ using CoupledSolid< SOLID_TYPE, ReactivePorosity, PERM_TYPE >::getPermModel;
+};
+
+
+
+}
+} /* namespace geos */
+
+#endif /* GEOS_CONSTITUTIVE_SOLID_POROUSREACTIVESOLID_HPP_ */
diff --git a/src/coreComponents/constitutive/solid/ReactiveSolid.cpp b/src/coreComponents/constitutive/solid/ReactiveSolid.cpp
new file mode 100644
index 00000000000..eb015de05f4
--- /dev/null
+++ b/src/coreComponents/constitutive/solid/ReactiveSolid.cpp
@@ -0,0 +1,55 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ReactiveSolid.cpp
+ */
+
+#include "ReactiveSolid.hpp"
+#include "porosity/ReactivePorosity.hpp"
+#include "constitutive/permeability/ConstantPermeability.hpp"
+#include "constitutive/permeability/CarmanKozenyPermeability.hpp"
+#include "constitutive/permeability/PressurePermeability.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+namespace constitutive
+{
+
+template< typename PORO_TYPE,
+ typename PERM_TYPE >
+ReactiveSolid< PORO_TYPE, PERM_TYPE >::ReactiveSolid( string const & name, Group * const parent ):
+ CoupledSolid< NullModel, PORO_TYPE, PERM_TYPE >( name, parent )
+{}
+
+template< typename PORO_TYPE,
+ typename PERM_TYPE >
+ReactiveSolid< PORO_TYPE, PERM_TYPE >::~ReactiveSolid() = default;
+
+// Register all ReactiveSolid model types.
+typedef ReactiveSolid< ReactivePorosity, ConstantPermeability > ReactiveRockConstant;
+typedef ReactiveSolid< ReactivePorosity, CarmanKozenyPermeability > ReactiveRockCK;
+typedef ReactiveSolid< ReactivePorosity, PressurePermeability > ReactiveRockPressurePerm;
+
+REGISTER_CATALOG_ENTRY( ConstitutiveBase, ReactiveRockConstant, string const &, Group * const )
+REGISTER_CATALOG_ENTRY( ConstitutiveBase, ReactiveRockCK, string const &, Group * const )
+REGISTER_CATALOG_ENTRY( ConstitutiveBase, ReactiveRockPressurePerm, string const &, Group * const )
+
+}
+} /* namespace geos */
diff --git a/src/coreComponents/constitutive/solid/ReactiveSolid.hpp b/src/coreComponents/constitutive/solid/ReactiveSolid.hpp
new file mode 100644
index 00000000000..2c489ba92b5
--- /dev/null
+++ b/src/coreComponents/constitutive/solid/ReactiveSolid.hpp
@@ -0,0 +1,186 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ReactiveSolid.hpp
+ */
+
+#ifndef GEOS_CONSTITUTIVE_SOLID_REACTIVESOLID_HPP_
+#define GEOS_CONSTITUTIVE_SOLID_REACTIVESOLID_HPP_
+
+#include "constitutive/solid/CoupledSolid.hpp"
+#include "constitutive/solid/porosity/ReactivePorosity.hpp"
+#include "constitutive/NullModel.hpp"
+
+#include "constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp"
+
+namespace geos
+{
+namespace constitutive
+{
+
+/**
+ * @brief Provides kernel-callable constitutive update routines
+ *
+ *
+ * @tparam PORO_TYPE type of the porosity model
+ * @tparam PERM_TYPE type of the permeability model
+ */
+template< typename PORO_TYPE,
+ typename PERM_TYPE >
+class ReactiveSolidUpdates : public CoupledSolidUpdates< NullModel, PORO_TYPE, PERM_TYPE >
+{
+public:
+
+ /**
+ * @brief Constructor
+ */
+ ReactiveSolidUpdates( NullModel const & solidModel,
+ PORO_TYPE const & porosityModel,
+ PERM_TYPE const & permModel ):
+ CoupledSolidUpdates< NullModel, PORO_TYPE, PERM_TYPE >( solidModel, porosityModel, permModel )
+ {}
+
+ GEOS_HOST_DEVICE
+ virtual void updateStateFromPressureTemperatureAndReactions( localIndex const k,
+ localIndex const q,
+ real64 const & pressure,
+ real64 const & temperature,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & kineticReactionMolarIncrements ) const override final
+ {
+ GEOS_UNUSED_VAR( temperature );
+
+ m_porosityUpdate.updateFromReactions( k, q, kineticReactionMolarIncrements );
+ real64 const porosity = m_porosityUpdate.getPorosity( k, q );
+ m_permUpdate.updateFromPressureAndPorosity( k, q, pressure, porosity );
+ }
+
+ GEOS_HOST_DEVICE
+ virtual void updateSurfaceArea( localIndex const k,
+ localIndex const q,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & initialSurfaceArea,
+ arraySlice1d< real64, compflow::USD_COMP - 1 > const & surfaceArea ) const override final
+ {
+ real64 const porosity = m_porosityUpdate.getPorosity( k, q );
+ real64 const initialPorosity = m_porosityUpdate.getInitialPorosity( k, q );
+
+ for( integer r=0; r < initialSurfaceArea.size(); ++r )
+ {
+ real64 const volumeFraction_r = m_porosityUpdate.getVolumeFractionForMineral( k, q, r );
+ real64 const initialVolumeFraction_r = m_porosityUpdate.getInitialVolumeFractionForMineral( k, q, r );
+ surfaceArea[r] = initialSurfaceArea[r] * pow( volumeFraction_r / initialVolumeFraction_r, 2.0/3.0 )
+ * pow( porosity / initialPorosity, 2.0/3.0 );
+ }
+ }
+
+private:
+ using CoupledSolidUpdates< NullModel, ReactivePorosity, PERM_TYPE >::m_solidUpdate;
+ using CoupledSolidUpdates< NullModel, ReactivePorosity, PERM_TYPE >::m_porosityUpdate;
+ using CoupledSolidUpdates< NullModel, ReactivePorosity, PERM_TYPE >::m_permUpdate;
+
+};
+
+
+/**
+ * @brief ReactiveSolidBase class used for dispatch of all Reactive solids.
+ */
+class ReactiveSolidBase
+{};
+
+
+/**
+ * @brief Class to represent a porous material for flow simulations.
+ * It is used as an interface to access all constitutive models relative to the properties of a porous material
+ * for flow only simulations.
+ *
+ * @tparam PORO_TYPE type of porosity model
+ * @tparam PERM_TYPE type of the permeability model
+ */
+
+template< typename PORO_TYPE,
+ typename PERM_TYPE >
+class ReactiveSolid : public CoupledSolid< NullModel, PORO_TYPE, PERM_TYPE >
+{
+public:
+
+
+ /// Alias for ElasticIsotropicUpdates
+ using KernelWrapper = ReactiveSolidUpdates< PORO_TYPE, PERM_TYPE >;
+
+ /**
+ * @brief Constructor
+ * @param name Object name
+ * @param parent Object's parent group
+ */
+ ReactiveSolid( string const & name, dataRepository::Group * const parent );
+
+ /// Destructor
+ virtual ~ReactiveSolid() override;
+
+ /**
+ * @brief Catalog name
+ * @return Static catalog string
+ */
+ static string catalogName() { return string( "ReactiveSolid" ) + PERM_TYPE::catalogName(); }
+
+ /**
+ * @brief Get catalog name
+ * @return Catalog name string
+ */
+ virtual string getCatalogName() const override { return catalogName(); }
+
+ /*
+ * @brief get the volume fractions.
+ * return a constant arrayView3d to the new volume fractions
+ */
+ arrayView3d< real64 const > const getVolumeFractions() const
+ {
+ return getPorosityModel().getVolumeFractions();
+ }
+
+ /*
+ * @brief get the initial volume fractions.
+ * return a constant arrayView1d to the initial volume fractions
+ */
+ arrayView1d< real64 const > const getInitialVolumeFractions() const
+ {
+ return getPorosityModel().getInitialVolumeFractions();
+ }
+
+
+ /**
+ * @brief Create a instantiation of the ReactiveSolidUpdates class
+ * that refers to the data in this.
+ * @return An instantiation of ReactiveSolidUpdates.
+ */
+ KernelWrapper createKernelUpdates() const
+ {
+
+ return ReactiveSolidUpdates< PORO_TYPE, PERM_TYPE >( getSolidModel(),
+ getPorosityModel(),
+ getPermModel() );
+ }
+private:
+ using CoupledSolid< NullModel, PORO_TYPE, PERM_TYPE >::getSolidModel;
+ using CoupledSolid< NullModel, PORO_TYPE, PERM_TYPE >::getPorosityModel;
+ using CoupledSolid< NullModel, PORO_TYPE, PERM_TYPE >::getPermModel;
+
+};
+
+}
+} /* namespace geos */
+
+#endif /* GEOS_CONSTITUTIVE_SOLID_REACTIVESOLID_HPP_ */
diff --git a/src/coreComponents/constitutive/solid/porosity/ReactivePorosity.cpp b/src/coreComponents/constitutive/solid/porosity/ReactivePorosity.cpp
new file mode 100644
index 00000000000..7865764fd7c
--- /dev/null
+++ b/src/coreComponents/constitutive/solid/porosity/ReactivePorosity.cpp
@@ -0,0 +1,144 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ReactivePorosity.cpp
+ */
+
+#include "ReactivePorosity.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+namespace constitutive
+{
+
+ReactivePorosity::ReactivePorosity( string const & name, Group * const parent ):
+ PorosityBase( name, parent )
+{
+ registerWrapper( viewKeyStruct::defaultInitialVolumeFractionsString(), &m_defaultInitialVolumeFractions ).
+ setInputFlag( InputFlags::REQUIRED ).
+ setDescription( "Default initial volume fractions" );
+
+ registerWrapper( viewKeyStruct::initialVolumeFractionsString(), &m_initialVolumeFractions ).
+ setApplyDefaultValue( 0.0 ).
+ setPlotLevel( PlotLevel::LEVEL_0 ).
+ setDescription( "Initial volume fractions" );
+
+ registerWrapper( viewKeyStruct::volumeFractionsString(), &m_volumeFractions ).
+ setApplyDefaultValue( 0.0 ).
+ setPlotLevel( PlotLevel::LEVEL_0 ).
+ setDescription( "Current volume fractions" );
+
+ registerWrapper( viewKeyStruct::volumeFractions_nString(), &m_volumeFractions_n ).
+ setApplyDefaultValue( 0.0 ).
+ setPlotLevel( PlotLevel::LEVEL_0 ).
+ setDescription( "Volume fractions at last time step" );
+
+ registerWrapper( viewKeyStruct::molarWeightsString(), &m_molarWeights ).
+ setInputFlag( InputFlags::REQUIRED ).
+ setDescription( "Mineral molar weights" );
+
+ registerWrapper( viewKeyStruct::mineralDensitiesString(), &m_mineralDensities ).
+ setInputFlag( InputFlags::REQUIRED ).
+ setDescription( "Mineral densities" );
+}
+
+std::unique_ptr< ConstitutiveBase > ReactivePorosity::deliverClone( string const & name, Group * const parent ) const
+{
+ std::unique_ptr< ConstitutiveBase > clone = ConstitutiveBase::deliverClone( name, parent );
+
+ ReactivePorosity & newConstitutiveRelation = dynamicCast< ReactivePorosity & >( *clone );
+
+ newConstitutiveRelation.m_numKineticReactions = m_numKineticReactions;
+
+ return clone;
+}
+
+void ReactivePorosity::postInputInitialization()
+{
+ PorosityBase::postInputInitialization();
+
+ GEOS_THROW_IF_NE_MSG( m_molarWeights.size(), m_defaultInitialVolumeFractions.size(),
+ GEOS_FMT( "{}: mismatch in number of components in porosity model attribute '{}' and '{}",
+ getFullName(), viewKeyStruct::molarWeightsString(), viewKeyStruct::initialVolumeFractionsString() ),
+ InputError );
+
+ GEOS_THROW_IF_NE_MSG( m_mineralDensities.size(), m_defaultInitialVolumeFractions.size(),
+ GEOS_FMT( "{}: mismatch in number of components in porosity model attribute '{}' and '{}",
+ getFullName(), viewKeyStruct::mineralDensitiesString(), viewKeyStruct::initialVolumeFractionsString() ),
+ InputError );
+
+ m_numKineticReactions = m_defaultInitialVolumeFractions.size();
+}
+
+void ReactivePorosity::allocateConstitutiveData( dataRepository::Group & parent,
+ localIndex const numConstitutivePointsPerParentIndex )
+{
+ PorosityBase::allocateConstitutiveData( parent, numConstitutivePointsPerParentIndex );
+
+ resizeFields( parent.size(), numConstitutivePointsPerParentIndex );
+
+}
+
+void ReactivePorosity::resizeFields( localIndex const size, localIndex const numPts )
+{
+ integer const numKineticReactions = this->numKineticReactions();
+
+ m_initialVolumeFractions.resize( size, numPts, numKineticReactions );
+ m_volumeFractions.resize( size, numPts, numKineticReactions );
+ m_volumeFractions_n.resize( size, numPts, numKineticReactions );
+}
+
+void ReactivePorosity::saveConvergedState() const
+{
+ PorosityBase::saveConvergedState();
+
+ m_volumeFractions_n.setValues< parallelDevicePolicy<> >( m_volumeFractions.toViewConst() );
+}
+
+void ReactivePorosity::initializeState() const
+{
+ integer const numKineticReactions = this->numKineticReactions();
+
+ for( localIndex ei = 0; ei < m_newPorosity.size( 0 ); ++ei )
+ {
+ for( localIndex q = 0; q < m_newPorosity.size( 1 ); ++q )
+ {
+ m_newPorosity[ei][q] = m_referencePorosity[ei];
+ }
+ }
+
+ PorosityBase::initializeState();
+
+ for( localIndex ei = 0; ei < m_volumeFractions.size( 0 ); ++ei )
+ {
+ for( localIndex q = 0; q < m_volumeFractions.size( 1 ); ++q )
+ {
+ for( integer r = 0; r < numKineticReactions; ++r )
+ {
+ m_volumeFractions[ei][q][r] = m_defaultInitialVolumeFractions[r];
+ m_initialVolumeFractions[ei][q][r] = m_defaultInitialVolumeFractions[r];
+ m_volumeFractions_n[ei][q][r] = m_defaultInitialVolumeFractions[r];
+ }
+ }
+ }
+}
+
+REGISTER_CATALOG_ENTRY( ConstitutiveBase, ReactivePorosity, string const &, Group * const )
+}
+} /* namespace geos */
diff --git a/src/coreComponents/constitutive/solid/porosity/ReactivePorosity.hpp b/src/coreComponents/constitutive/solid/porosity/ReactivePorosity.hpp
new file mode 100644
index 00000000000..adafd421783
--- /dev/null
+++ b/src/coreComponents/constitutive/solid/porosity/ReactivePorosity.hpp
@@ -0,0 +1,233 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ReactivePorosity.hpp
+ */
+
+#ifndef GEOS_CONSTITUTIVE_POROSITY_REACTIVEPOROSITY_HPP_
+#define GEOS_CONSTITUTIVE_POROSITY_REACTIVEPOROSITY_HPP_
+
+#include "PorosityBase.hpp"
+
+#include "constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp"
+
+namespace geos
+{
+namespace constitutive
+{
+
+class ReactivePorosityUpdates : public PorosityBaseUpdates
+{
+public:
+
+ ReactivePorosityUpdates( arrayView2d< real64 > const & newPorosity,
+ arrayView2d< real64 const > const & porosity_n,
+ arrayView2d< real64 > const & dPorosity_dPressure,
+ arrayView2d< real64 > const & dPorosity_dTemperature,
+ arrayView2d< real64 const > const & initialPorosity,
+ arrayView1d< real64 const > const & referencePorosity,
+ arrayView3d< real64, reactivefluid::USD_SPECIES > const & volumeFractions,
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const & initialVolumeFractions,
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const & volumeFractions_n,
+ integer const numKineticReactions,
+ arrayView1d< real64 const > const & molarWeights,
+ arrayView1d< real64 const > const & mineralDensities ):
+ PorosityBaseUpdates( newPorosity,
+ porosity_n,
+ dPorosity_dPressure,
+ dPorosity_dTemperature,
+ initialPorosity,
+ referencePorosity ),
+ m_volumeFractions( volumeFractions ),
+ m_initialVolumeFractions( initialVolumeFractions ),
+ m_volumeFractions_n( volumeFractions_n ),
+ m_numKineticReactions( numKineticReactions ),
+ m_molarWeights( molarWeights ),
+ m_mineralDensities( mineralDensities )
+ {}
+
+ GEOS_HOST_DEVICE
+ void computePorosity( arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & kineticReactionMolarIncrements,
+ arraySlice1d< real64, reactivefluid::USD_SPECIES - 2 > const & volumeFractions,
+ arraySlice1d< real64 const, reactivefluid::USD_SPECIES - 2 > const & volumeFractions_n,
+ real64 & porosity,
+ real64 const & porosity_n,
+ integer const & numKineticReactions,
+ arrayView1d< real64 const > const & molarWeights,
+ arrayView1d< real64 const > const & mineralDensities ) const
+ {
+ real64 porosityIncrement = 0.0;
+
+ for( integer r=0; r < numKineticReactions; ++r )
+ {
+ real64 const volumeFractionIncrement = kineticReactionMolarIncrements[r] * molarWeights[r]/mineralDensities[r];
+ volumeFractions[r] = volumeFractions_n[r] + volumeFractionIncrement;
+
+ porosityIncrement += volumeFractionIncrement;
+ }
+
+ porosity = porosity_n + porosityIncrement; // To check if it should be plus or minus
+
+ if( porosity < 0 )
+ {
+ porosity = 0;
+ }
+ else if( porosity > 1.0 )
+ {
+ porosity = 1.0;
+ }
+
+ }
+
+ GEOS_HOST_DEVICE
+ void updateFromReactions( localIndex const k,
+ localIndex const q,
+ arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & kineticReactionMolarIncrements ) const
+ {
+ computePorosity( kineticReactionMolarIncrements,
+ m_volumeFractions[k][q],
+ m_volumeFractions_n[k][q],
+ m_newPorosity[k][q],
+ m_porosity_n[k][q],
+ m_numKineticReactions,
+ m_molarWeights,
+ m_mineralDensities );
+ }
+
+ GEOS_HOST_DEVICE
+ inline
+ real64 getVolumeFractionForMineral( localIndex const k,
+ localIndex const q,
+ localIndex const r ) const
+ {
+ return m_volumeFractions[k][q][r];
+ }
+
+ GEOS_HOST_DEVICE
+ inline
+ real64 getInitialVolumeFractionForMineral( localIndex const k,
+ localIndex const q,
+ localIndex const r ) const
+ {
+ return m_initialVolumeFractions[k][q][r];
+ }
+
+ GEOS_HOST_DEVICE
+ inline
+ real64 getMolarWeights( localIndex const r ) const
+ {
+ return m_molarWeights[r];
+ }
+
+ GEOS_HOST_DEVICE
+ inline
+ real64 getMineralDensities( localIndex const r ) const
+ {
+ return m_mineralDensities[r];
+ }
+
+protected:
+
+ arrayView3d< real64, reactivefluid::USD_SPECIES > m_volumeFractions;
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > m_initialVolumeFractions;
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const m_volumeFractions_n;
+
+ integer const m_numKineticReactions;
+ arrayView1d< real64 const > const m_molarWeights;
+ arrayView1d< real64 const > const m_mineralDensities;
+};
+
+
+class ReactivePorosity : public PorosityBase
+{
+public:
+ ReactivePorosity( string const & name, Group * const parent );
+
+ virtual std::unique_ptr< ConstitutiveBase >
+ deliverClone( string const & name,
+ dataRepository::Group * const parent ) const override;
+
+ virtual void allocateConstitutiveData( dataRepository::Group & parent,
+ localIndex const numConstitutivePointsPerParentIndex ) override;
+
+ static string catalogName() { return "ReactivePorosity"; }
+
+ virtual string getCatalogName() const override { return catalogName(); }
+
+ virtual void saveConvergedState() const override;
+
+ integer numKineticReactions() const { return m_numKineticReactions; }
+
+ virtual void initializeState() const override;
+
+ struct viewKeyStruct : public PorosityBase::viewKeyStruct
+ {
+ static constexpr char const * defaultInitialVolumeFractionsString() { return "defaultInitialVolumeFractions"; }
+ static constexpr char const * initialVolumeFractionsString() { return "initialVolumeFractions"; }
+ static constexpr char const * volumeFractionsString() { return "volumeFractions"; }
+ static constexpr char const * volumeFractions_nString() { return "volumeFractions_n"; }
+ static constexpr char const * molarWeightsString() { return "molarWeights"; }
+ static constexpr char const * mineralDensitiesString() { return "mineralDensities"; }
+ } viewKeys;
+
+
+ using KernelWrapper = ReactivePorosityUpdates;
+
+ /**
+ * @brief Create an update kernel wrapper.
+ * @return the wrapper
+ */
+ KernelWrapper createKernelUpdates() const
+ {
+ return KernelWrapper( m_newPorosity,
+ m_porosity_n,
+ m_dPorosity_dPressure,
+ m_dPorosity_dTemperature,
+ m_initialPorosity,
+ m_referencePorosity,
+ m_volumeFractions,
+ m_initialVolumeFractions,
+ m_volumeFractions_n,
+ m_numKineticReactions,
+ m_molarWeights,
+ m_mineralDensities );
+ }
+
+
+private:
+ virtual void postInputInitialization() override;
+
+ virtual void resizeFields( localIndex const size, localIndex const numPts );
+
+ array1d< real64 > m_defaultInitialVolumeFractions;
+
+ array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES > m_volumeFractions;
+ array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES > m_initialVolumeFractions;
+ array3d< real64, constitutive::reactivefluid::LAYOUT_SPECIES > m_volumeFractions_n;
+
+ integer m_numKineticReactions;
+ array1d< real64 > m_molarWeights;
+ array1d< real64 > m_mineralDensities;
+
+};
+
+
+}/* namespace constitutive */
+
+} /* namespace geos */
+
+
+#endif //GEOS_CONSTITUTIVE_POROSITY_REACTIVEPOROSITY_HPP_
diff --git a/src/coreComponents/constitutiveDrivers/CMakeLists.txt b/src/coreComponents/constitutiveDrivers/CMakeLists.txt
index eac876388b2..0d79d151661 100644
--- a/src/coreComponents/constitutiveDrivers/CMakeLists.txt
+++ b/src/coreComponents/constitutiveDrivers/CMakeLists.txt
@@ -25,7 +25,6 @@ set( constitutiveDrivers_headers
fluid/multiFluid/LogLevelsInfo.hpp
fluid/multiFluid/PVTDriver.hpp
fluid/multiFluid/PVTDriverRunTest.hpp
- fluid/multiFluid/reactive/ReactiveFluidDriver.hpp
relativePermeability/RelpermDriver.hpp
relativePermeability/RelpermDriverRunTest.hpp
solid/TriaxialDriver.hpp
@@ -45,7 +44,6 @@ set( constitutiveDrivers_sources
fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhaseConstantViscosity.cpp
fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhasePhillipsBrine.cpp
fluid/multiFluid/compositional/PVTDriverRunTestCompositionalTwoPhaseLohrenzBrayClarkViscosity.cpp
- fluid/multiFluid/reactive/ReactiveFluidDriver.cpp
relativePermeability/RelpermDriver.cpp
relativePermeability/RelpermDriverBrooksCoreyBakerRunTest.cpp
relativePermeability/RelpermDriverBrooksCoreyStone2RunTest.cpp
diff --git a/src/coreComponents/integrationTests/constitutiveTests/CMakeLists.txt b/src/coreComponents/integrationTests/constitutiveTests/CMakeLists.txt
index 6a9957547f7..bbb94f47a59 100644
--- a/src/coreComponents/integrationTests/constitutiveTests/CMakeLists.txt
+++ b/src/coreComponents/integrationTests/constitutiveTests/CMakeLists.txt
@@ -22,9 +22,6 @@ set( gtest_pvt_xmls
testPVT_ThreePhaseCompositional.xml
)
-set( gtest_reactivefluid_xmls
- testReactiveFluid.xml )
-
set( tplDependencyList ${parallelDeps} gtest )
set( dependencyList mainInterface )
@@ -67,16 +64,3 @@ foreach(test ${gtest_pvt_xmls})
geos_add_test( NAME ${test_name}
COMMAND testPVT -i ${CMAKE_CURRENT_LIST_DIR}/${test} )
endforeach()
-
-
-# Add reactivefluiddriver xml based tests
-blt_add_executable( NAME testReactiveFluid
- SOURCES testReactiveFluid.cpp
- OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY}
- DEPENDS_ON ${dependencyList} "-lz" ${tplDependencyList} )
-
-foreach(test ${gtest_reactivefluid_xmls})
- get_filename_component( test_name ${test} NAME_WE )
- geos_add_test( NAME ${test_name}
- COMMAND testReactiveFluid -i ${CMAKE_CURRENT_LIST_DIR}/${test} )
-endforeach()
diff --git a/src/coreComponents/integrationTests/fluidFlowTests/CMakeLists.txt b/src/coreComponents/integrationTests/fluidFlowTests/CMakeLists.txt
index 129b10676c6..47fa7f990eb 100644
--- a/src/coreComponents/integrationTests/fluidFlowTests/CMakeLists.txt
+++ b/src/coreComponents/integrationTests/fluidFlowTests/CMakeLists.txt
@@ -4,7 +4,8 @@ set( gtest_geosx_tests
testThermalSinglePhaseFlow.cpp
testTransmissibility.cpp
testImmiscibleMultiphaseFlow.cpp
- testSinglePhaseMFDPolyhedral.cpp )
+ testSinglePhaseMFDPolyhedral.cpp
+ testSinglePhaseReactiveTransport.cpp )
if( ENABLE_PVTPackage )
list( APPEND gtest_geosx_tests
diff --git a/src/coreComponents/integrationTests/fluidFlowTests/testSinglePhaseReactiveTransport.cpp b/src/coreComponents/integrationTests/fluidFlowTests/testSinglePhaseReactiveTransport.cpp
new file mode 100644
index 00000000000..25074a146e9
--- /dev/null
+++ b/src/coreComponents/integrationTests/fluidFlowTests/testSinglePhaseReactiveTransport.cpp
@@ -0,0 +1,570 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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/singlefluid/SingleFluidBase.hpp"
+#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp"
+#include "finiteVolume/FiniteVolumeManager.hpp"
+#include "finiteVolume/FluxApproximationBase.hpp"
+#include "mainInterface/initialization.hpp"
+#include "mainInterface/GeosxState.hpp"
+#include "physicsSolvers/PhysicsSolverManager.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseReactiveTransportFields.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseReactiveTransport.hpp"
+#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp"
+#include "integrationTests/fluidFlowTests/testSinglePhaseReactiveTransportUtils.hpp"
+
+using namespace geos;
+using namespace geos::dataRepository;
+using namespace geos::constitutive;
+using namespace geos::constitutive::reactivefluid;
+using namespace geos::testing;
+
+CommandLineOptions g_commandLineOptions;
+
+// Sphinx start after input XML
+
+char const * xmlInputCarbonate =
+ R"xml(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )xml";
+// Sphinx end before input XML
+
+template< typename LAMBDA >
+void testNumericalJacobian( SinglePhaseReactiveTransport & solver,
+ DomainPartition & domain,
+ real64 const perturbParameter,
+ real64 const relTol,
+ LAMBDA assembleFunction )
+{
+ CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix();
+ array1d< real64 > residual( jacobian.numRows() );
+
+ // assemble the analytical residual
+ solver.resetStateToBeginningOfStep( domain );
+
+ residual.zero();
+ jacobian.zero();
+
+ assembleFunction( jacobian.toViewConstSizes(), residual.toView() );
+ residual.move( hostMemorySpace, false );
+
+ // copy the analytical residual
+ array1d< real64 > residualOrig( residual );
+
+ // create the numerical jacobian
+ jacobian.move( hostMemorySpace );
+ CRSMatrix< real64, globalIndex > jacobianFD( jacobian );
+ jacobianFD.zero();
+
+ // fill jacobian FD
+ fillCellCenteredNumericalJacobian( solver,
+ domain,
+ false,
+ perturbParameter,
+ residual.toView(),
+ residualOrig.toView(),
+ jacobian.toView(),
+ jacobianFD.toView(),
+ assembleFunction );
+
+ // assemble the analytical jacobian
+ solver.resetStateToBeginningOfStep( domain );
+
+ residual.zero();
+ jacobian.zero();
+ assembleFunction( jacobian.toViewConstSizes(), residual.toView() );
+
+ compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol, 1e-6 );
+}
+
+class SinglePhaseReactiveTransportTest : public ::testing::Test
+{
+public:
+
+ SinglePhaseReactiveTransportTest():
+ state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) )
+ {}
+
+protected:
+
+ void SetUp() override
+ {
+
+ setupProblemFromXML( state.getProblemManager(), xmlInputCarbonate );
+ solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< SinglePhaseReactiveTransport >( "SinglePhaseReactiveFlow" );
+
+ DomainPartition & domain = state.getProblemManager().getDomainPartition();
+
+ solver->setupSystem( domain,
+ solver->getDofManager(),
+ solver->getLocalMatrix(),
+ solver->getSystemRhs(),
+ solver->getSystemSolution() );
+
+ solver->implicitStepSetup( time, dt, domain );
+ }
+
+ static real64 constexpr time = 0.0;
+ static real64 constexpr dt = 1000;
+ static real64 constexpr eps = std::numeric_limits< real64 >::epsilon();
+
+ GeosxState state;
+ SinglePhaseReactiveTransport * solver;
+};
+
+real64 constexpr SinglePhaseReactiveTransportTest::time;
+real64 constexpr SinglePhaseReactiveTransportTest::dt;
+real64 constexpr SinglePhaseReactiveTransportTest::eps;
+
+TEST_F( SinglePhaseReactiveTransportTest, jacobianNumericalCheck_flux )
+{
+ real64 const perturb = std::sqrt( eps );
+ real64 const tol = 1e-10; // 1% error margin
+
+ DomainPartition & domain = state.getProblemManager().getDomainPartition();
+
+ testNumericalJacobian( *solver, domain, perturb, tol,
+ [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ // The first input parameter denotes t_n, which is unused. Just input something here.
+ solver->assembleFluxTerms( dt, domain, solver->getDofManager(), localMatrix, localRhs );
+ } );
+}
+
+TEST_F( SinglePhaseReactiveTransportTest, jacobianNumericalCheck_accumulationBalance )
+{
+ real64 const perturb = std::sqrt( eps );
+ real64 const tol = 1e-6; // 1% error margin
+
+ DomainPartition & domain = state.getProblemManager().getDomainPartition();
+
+ testNumericalJacobian( *solver, domain, perturb, tol,
+ [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ solver->assembleAccumulationTermsInMassBalanceAndSpeciesAmountEqs( dt, domain, solver->getDofManager(), localMatrix, localRhs );
+ } );
+}
+
+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;
+}
diff --git a/src/coreComponents/integrationTests/fluidFlowTests/testSinglePhaseReactiveTransportUtils.hpp b/src/coreComponents/integrationTests/fluidFlowTests/testSinglePhaseReactiveTransportUtils.hpp
new file mode 100644
index 00000000000..2cd58eeb87d
--- /dev/null
+++ b/src/coreComponents/integrationTests/fluidFlowTests/testSinglePhaseReactiveTransportUtils.hpp
@@ -0,0 +1,227 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+
+#ifndef GEOS_TESTSINGLEPHASEREACTIVETRANSPORTUTILS_HPP
+#define GEOS_TESTSINGLEPHASEREACTIVETRANSPORTUTILS_HPP
+
+#include "codingUtilities/UnitTestUtilities.hpp"
+#include "constitutive/ConstitutiveManager.hpp"
+#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp"
+#include "constitutive/fluid/singlefluid/SingleFluidLayouts.hpp"
+#include "mesh/MeshManager.hpp"
+#include "mainInterface/ProblemManager.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseReactiveTransportFields.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseReactiveTransport.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseFVM.hpp"
+#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp"
+#include "testFlowUtils.hpp"
+
+namespace geos
+{
+
+namespace testing
+{
+
+void fillNumericalJacobian( arrayView1d< real64 const > const & residual,
+ arrayView1d< real64 const > const & residualOrig,
+ globalIndex const dofIndex,
+ real64 const eps,
+ CRSMatrixView< real64, globalIndex const > const & jacobian )
+{
+ forAll< parallelDevicePolicy<> >( residual.size(), [=] GEOS_HOST_DEVICE ( localIndex const row )
+ {
+ real64 const dRdX = ( residual[row] - residualOrig[row] ) / eps;
+ if( fabs( dRdX ) > 0.0 )
+ {
+ jacobian.addToRow< parallelDeviceAtomic >( row, &dofIndex, &dRdX, 1 );
+ }
+ } );
+}
+
+void setupProblemFromXML( ProblemManager & problemManager, char const * const xmlInput )
+{
+ xmlWrapper::xmlDocument xmlDocument;
+ xmlWrapper::xmlResult xmlResult = xmlDocument.loadString( xmlInput );
+ if( !xmlResult )
+ {
+ GEOS_LOG_RANK_0( "XML parsed with errors!" );
+ GEOS_LOG_RANK_0( "Error description: " << xmlResult.description());
+ GEOS_LOG_RANK_0( "Error offset: " << xmlResult.offset );
+ }
+
+ int mpiSize = MpiWrapper::commSize( MPI_COMM_GEOS );
+
+ dataRepository::Group & commandLine =
+ problemManager.getGroup< dataRepository::Group >( problemManager.groupKeys.commandLine );
+
+ commandLine.registerWrapper< integer >( problemManager.viewKeys.xPartitionsOverride.key() ).
+ setApplyDefaultValue( mpiSize );
+
+ xmlWrapper::xmlNode xmlProblemNode = xmlDocument.getChild( dataRepository::keys::ProblemManager );
+ problemManager.processInputFileRecursive( xmlDocument, xmlProblemNode );
+
+ DomainPartition & domain = problemManager.getDomainPartition();
+
+ constitutive::ConstitutiveManager & constitutiveManager = domain.getConstitutiveManager();
+ xmlWrapper::xmlNode topLevelNode = xmlProblemNode.child( constitutiveManager.getName().c_str());
+ constitutiveManager.processInputFileRecursive( xmlDocument, topLevelNode );
+
+ MeshManager & meshManager = problemManager.getGroup< MeshManager >( problemManager.groupKeys.meshManager );
+ meshManager.generateMeshLevels( domain );
+
+ ElementRegionManager & elementManager = domain.getMeshBody( 0 ).getBaseDiscretization().getElemManager();
+ topLevelNode = xmlProblemNode.child( elementManager.getName().c_str());
+ elementManager.processInputFileRecursive( xmlDocument, topLevelNode );
+
+ problemManager.problemSetup();
+ problemManager.applyInitialConditions();
+}
+
+template< typename SINGLE_REACTIVE_TRANSPORT_SOLVER, typename LAMBDA >
+void fillCellCenteredNumericalJacobian( SINGLE_REACTIVE_TRANSPORT_SOLVER & solver,
+ DomainPartition & domain,
+ bool const isThermal,
+ real64 const perturbParameter,
+ arrayView1d< real64 > residual,
+ arrayView1d< real64 > residualOrig,
+ CRSMatrixView< real64, globalIndex > jacobian,
+ CRSMatrixView< real64, globalIndex > jacobianFD,
+ LAMBDA assembleFunction )
+{
+ integer const numSpecies = solver.numPrimarySpecies();
+
+ DofManager const & dofManager = solver.getDofManager();
+ string const elemDofKey = dofManager.getKey( SINGLE_REACTIVE_TRANSPORT_SOLVER::viewKeyStruct::elemDofFieldString() );
+
+ solver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions( regionNames,
+ [&]( localIndex const,
+ ElementSubRegionBase & subRegion )
+ {
+ arrayView1d< integer const > const & elemGhostRank = subRegion.ghostRank();
+ arrayView1d< globalIndex const > const & elemDofNumber =
+ subRegion.getReference< array1d< globalIndex > >( elemDofKey );
+
+ arrayView1d< real64 > const pres =
+ subRegion.getField< fields::flow::pressure >();
+ arrayView2d< real64, compflow::USD_COMP > const logPrimaryConc =
+ subRegion.getField< fields::flow::logPrimarySpeciesConcentration >();
+
+ for( localIndex ei = 0; ei < subRegion.size(); ++ei )
+ {
+ if( elemGhostRank[ei] >= 0 )
+ {
+ continue;
+ }
+
+ solver.resetStateToBeginningOfStep( domain );
+
+ // Step 1: compute numerical derivatives wrt pressure
+
+ {
+ pres.move( hostMemorySpace, true ); // to get the correct pres after reset
+ real64 const dP = perturbParameter * ( pres[ei] + perturbParameter );
+ pres[ei] += dP;
+#if defined(GEOS_USE_CUDA)
+ pres.move( parallelDeviceMemorySpace, false );
+#endif
+
+ solver.updateState( domain );
+
+ residual.zero();
+ jacobian.zero();
+ assembleFunction( jacobian.toViewConstSizes(), residual.toView() );
+
+ fillNumericalJacobian( residual.toViewConst(),
+ residualOrig.toViewConst(),
+ elemDofNumber[ei],
+ dP,
+ jacobianFD.toViewConstSizes() );
+ }
+
+ // Step 2: compute numerical derivatives wrt temperature
+
+ if( isThermal )
+ {
+ arrayView1d< real64 > const temp =
+ subRegion.getField< fields::flow::temperature >();
+ temp.move( hostMemorySpace, false );
+
+ solver.resetStateToBeginningOfStep( domain );
+
+ temp.move( hostMemorySpace, true );
+ real64 const dT = perturbParameter * ( temp[ei] + perturbParameter );
+ temp[ei] += dT;
+#if defined(GEOS_USE_CUDA)
+ temp.move( parallelDeviceMemorySpace, false );
+#endif
+
+ // here, we make sure that rock internal energy is updated
+ // in other words, a call to updateFluidState would not work
+ solver.updateState( domain );
+
+ residual.zero();
+ jacobian.zero();
+ assembleFunction( jacobian.toViewConstSizes(), residual.toView() );
+
+ fillNumericalJacobian( residual.toViewConst(),
+ residualOrig.toViewConst(),
+ elemDofNumber[ei] + 1,
+ dT,
+ jacobianFD.toViewConstSizes() );
+ }
+
+ // Step 3: compute numerical derivatives wrt log primary species concentration
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ solver.resetStateToBeginningOfStep( domain );
+
+ logPrimaryConc.move( hostMemorySpace, true ); // to get the correct logPrimaryConc after reset
+ real64 const dConc = perturbParameter * ( logPrimaryConc[ei][is] + perturbParameter );
+ logPrimaryConc[ei][is] += dConc;
+#if defined(GEOS_USE_CUDA)
+ logPrimaryConc.move( parallelDeviceMemorySpace, false );
+#endif
+ solver.updateState( domain );
+
+ residual.zero();
+ jacobian.zero();
+ assembleFunction( jacobian.toViewConstSizes(), residual.toView() );
+
+ integer const speciesIndexShift = (isThermal)? 2:1;
+
+ fillNumericalJacobian( residual.toViewConst(),
+ residualOrig.toViewConst(),
+ elemDofNumber[ei] + speciesIndexShift + is,
+ dConc,
+ jacobianFD.toViewConstSizes() );
+ }
+
+ }
+ } );
+ } );
+}
+
+
+} // namespace testing
+
+} // namespace geos
+
+#endif //GEOS_TESTSINGLEPHASEREACTIVETRANSPORTUTILS_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
index 28ffa57e587..c406ebe631d 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
+++ b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
@@ -65,6 +65,16 @@ 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/ThermalAccumulationKernels.hpp
+ kernels/singlePhase/reactive/ThermalDirichletFluxComputeKernel.hpp
+ kernels/singlePhase/reactive/ThermalFluxComputeKernel.hpp
kernels/compositional/AccumulationKernel.hpp
kernels/compositional/AquiferBCKernel.hpp
kernels/compositional/PPUPhaseFlux.hpp
@@ -139,6 +149,7 @@ set( fluidFlowSolvers_sources
SinglePhaseFVM.cpp
SinglePhaseHybridFVM.cpp
SinglePhaseProppantBase.cpp
+ SinglePhaseReactiveTransport.cpp
SourceFluxStatistics.cpp
StencilDataCollection.cpp
kernels/singlePhase/proppant/ProppantFluxKernels.cpp
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp
index e67bae98e2e..8b68a5fad08 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp
@@ -105,7 +105,7 @@ class FlowSolverBase : public PhysicsSolverBase
void enableJumpStabilization() { m_isJumpStabilized = true; }
- void updatePorosityAndPermeability( CellElementSubRegion & subRegion ) const;
+ virtual void updatePorosityAndPermeability( CellElementSubRegion & subRegion ) const;
virtual void updatePorosityAndPermeability( SurfaceElementSubRegion & subRegion ) const;
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp
index d57772ffe81..069ac3dfb3c 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp
@@ -162,11 +162,11 @@ void SinglePhaseBase::validateConstitutiveModels( DomainPartition & domain ) con
constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid )
{
string const fluidModelName = castedFluid.getCatalogName();
- GEOS_THROW_IF( m_isThermal && (fluidModelName != "ThermalCompressibleSinglePhaseFluid"),
+ GEOS_THROW_IF( m_isThermal && ((fluidModelName != "ThermalCompressibleSinglePhaseFluid") && (fluidModelName != "ReactiveThermalCompressibleSinglePhaseFluid")),
GEOS_FMT( "SingleFluidBase {}: the thermal option is enabled in the solver, but the fluid model {} is not for thermal fluid",
getDataContext(), fluid.getDataContext() ),
InputError );
- GEOS_THROW_IF( !m_isThermal && (fluidModelName == "ThermalCompressibleSinglePhaseFluid"),
+ GEOS_THROW_IF( !m_isThermal && ((fluidModelName == "ThermalCompressibleSinglePhaseFluid") || (fluidModelName == "ReactiveThermalCompressibleSinglePhaseFluid")),
GEOS_FMT( "SingleFluidBase {}: the fluid model is for thermal fluid {}, but the solver option is incompatible with the fluid model",
getDataContext(), fluid.getDataContext() ),
InputError );
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp
index a9e0af8e961..87ff12f39f7 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp
@@ -223,7 +223,7 @@ class SinglePhaseBase : public FlowSolverBase
* @param localMatrix local system matrix
* @param localRhs local system right-hand side vector
*/
- void
+ virtual void
applyDirichletBC( real64 const time_n,
real64 const dt,
DomainPartition & domain,
@@ -240,7 +240,7 @@ class SinglePhaseBase : public FlowSolverBase
* @param localMatrix local system matrix
* @param localRhs local system right-hand side vector
*/
- void
+ virtual void
applySourceFluxBC( real64 const time_n,
real64 const dt,
DomainPartition & domain,
@@ -266,7 +266,7 @@ class SinglePhaseBase : public FlowSolverBase
arrayView1d< real64 > const & localRhs ) const = 0;
virtual void
- updateState ( DomainPartition & domain ) override final;
+ updateState ( DomainPartition & domain ) override;
/**
* @brief Function to update all constitutive state and dependent variables
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseReactiveTransport.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseReactiveTransport.cpp
new file mode 100644
index 00000000000..23fe8454a38
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseReactiveTransport.cpp
@@ -0,0 +1,1747 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 SinglePhaseReactiveTransport.cpp
+ */
+
+#include "SinglePhaseReactiveTransport.hpp"
+
+#include "constitutive/ConstitutiveManager.hpp"
+#include "constitutive/ConstitutivePassThru.hpp"
+#include "constitutive/diffusion/DiffusionFields.hpp"
+#include "constitutive/diffusion/DiffusionSelector.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.cpp"
+#include "constitutive/fluid/reactivefluid/ReactiveFluidSelector.hpp"
+#include "constitutive/solid/CoupledSolidBase.hpp"
+#include "constitutive/solid/ReactiveSolid.hpp"
+#include "fieldSpecification/FieldSpecificationManager.hpp"
+#include "fieldSpecification/SourceFluxBoundaryCondition.hpp"
+#include "physicsSolvers/fluidFlow/SourceFluxStatistics.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/KernelLaunchSelectors.hpp"
+#include "finiteVolume/FluxApproximationBase.hpp"
+#include "mesh/DomainPartition.hpp"
+#include "physicsSolvers/LogLevelsInfo.hpp"
+
+/**
+ * @namespace the geos namespace that encapsulates the majority of the code
+ */
+namespace geos
+{
+
+using namespace dataRepository;
+using namespace constitutive;
+
+template< typename POROUSWRAPPER_TYPE >
+void updatePorosityAndPermeabilityFromPressureTemperatureAndReactions( POROUSWRAPPER_TYPE porousWrapper,
+ ElementSubRegionBase & subRegion,
+ arrayView1d< real64 const > const & pressure,
+ arrayView1d< real64 const > const & temperature,
+ arrayView2d< real64 const, compflow::USD_COMP > const & kineticReactionMolarIncrements )
+{
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_DEVICE ( localIndex const k )
+ {
+ for( localIndex q = 0; q < porousWrapper.numGauss(); ++q )
+ {
+ porousWrapper.updateStateFromPressureTemperatureAndReactions( k, q,
+ pressure[k],
+ temperature[k],
+ kineticReactionMolarIncrements[k] );
+ }
+ } );
+}
+
+template< typename POROUSWRAPPER_TYPE >
+void updateSurfaceAreaFromReactions( POROUSWRAPPER_TYPE porousWrapper,
+ ElementSubRegionBase & subRegion,
+ arrayView2d< real64 const, compflow::USD_COMP > const & initialSurfaceArea,
+ arrayView2d< real64, compflow::USD_COMP > const & surfaceArea )
+{
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_DEVICE ( localIndex const k )
+ {
+ for( localIndex q = 0; q < porousWrapper.numGauss(); ++q )
+ {
+ porousWrapper.updateSurfaceArea( k, q,
+ initialSurfaceArea[k],
+ surfaceArea[k] );
+ }
+ } );
+}
+
+SinglePhaseReactiveTransport::SinglePhaseReactiveTransport( const string & name,
+ Group * const parent ):
+ SinglePhaseBase( name, parent ),
+ m_numPrimarySpecies( 0 ),
+ m_numKineticReactions( 0 ),
+ m_hasDiffusion( 0 ),
+ m_isUpdateReactivePorosity( 0 ),
+ m_isUpdateSurfaceArea( 0 )
+{
+ // To add modeling parameters we want to add here
+
+ this->registerWrapper( viewKeyStruct::isUpdateReactivePorosityString(), &m_isUpdateReactivePorosity ).
+ setApplyDefaultValue( 0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Flag indicating whether use the reactive porosity or not" );
+
+ this->registerWrapper( viewKeyStruct::isUpdateSurfaceAreaString(), &m_isUpdateSurfaceArea ).
+ setApplyDefaultValue( 0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Flag indicating whether to update the surface area or not" );
+
+ this->registerWrapper( viewKeyStruct::immobilePrimarySpeciesIndicesString(), &m_immobilePrimarySpeciesIndices ).
+ setApplyDefaultValue( { } ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Array to store the indices of immobile species. Default is {}, which indicates no immobile species." );
+
+ addLogLevel< logInfo::BoundaryConditions >();
+}
+
+void SinglePhaseReactiveTransport::registerDataOnMesh( Group & meshBodies )
+{
+ using namespace fields::flow;
+
+ SinglePhaseBase::registerDataOnMesh( meshBodies );
+
+ DomainPartition const & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" );
+ ConstitutiveManager const & cm = domain.getConstitutiveManager();
+
+ // 0. Find a reactive fluid model name (at this point, models are already attached to subregions)
+ forDiscretizationOnMeshTargets( meshBodies, [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions( regionNames,
+ [&]( localIndex const,
+ ElementSubRegionBase & subRegion )
+ {
+ if( m_reactiveFluidModelName.empty() )
+ {
+ m_reactiveFluidModelName = m_isThermal? getConstitutiveName< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >( subRegion ):
+ getConstitutiveName< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( subRegion );
+ }
+
+ // If at least one region has a diffusion model, consider it enabled for all
+ string const diffusionName = getConstitutiveName< DiffusionBase >( subRegion );
+ if( !diffusionName.empty() )
+ {
+ m_hasDiffusion = true;
+ }
+ } );
+ } );
+
+ // 1. Set key dimensions of the problem
+ // Check needed to avoid errors when running in schema generation mode.
+ if( !m_reactiveFluidModelName.empty() )
+ {
+ if( m_isThermal )
+ {
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid const & reactiveFluid = cm.getConstitutiveRelation< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >(
+ m_reactiveFluidModelName );
+ m_numPrimarySpecies = reactiveFluid.numPrimarySpecies();
+ m_numKineticReactions = reactiveFluid.numKineticReactions();
+ }
+ else
+ {
+ reactivefluid::ReactiveCompressibleSinglePhaseFluid const & reactiveFluid = cm.getConstitutiveRelation< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( m_reactiveFluidModelName );
+ m_numPrimarySpecies = reactiveFluid.numPrimarySpecies();
+ m_numKineticReactions = reactiveFluid.numKineticReactions();
+ }
+ }
+
+ // n_c components + one pressure ( + one temperature if needed )
+ m_numDofPerCell = m_isThermal ? m_numPrimarySpecies + 2 : m_numPrimarySpecies + 1;
+
+ // 2. Register and resize all fields as necessary
+ forDiscretizationOnMeshTargets( meshBodies, [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ ElementRegionManager & elemManager = mesh.getElemManager();
+
+ elemManager.forElementSubRegions< ElementSubRegionBase >( regionNames,
+ [&]( localIndex const,
+ ElementSubRegionBase & subRegion )
+ {
+ if( m_hasDiffusion )
+ {
+ subRegion.registerWrapper< string >( viewKeyStruct::diffusionNamesString() ).
+ setPlotLevel( PlotLevel::NOPLOT ).
+ setRestartFlags( RestartFlags::NO_WRITE ).
+ setSizedFromParent( 0 ).
+ setDescription( "Name of the diffusion constitutive model to use" );
+
+ string & diffusionName = subRegion.getReference< string >( viewKeyStruct::diffusionNamesString() );
+ diffusionName = getConstitutiveName< DiffusionBase >( subRegion );
+ GEOS_THROW_IF( diffusionName.empty(),
+ GEOS_FMT( "Diffusion model not found on subregion {}", subRegion.getName() ),
+ InputError );
+ }
+
+ subRegion.registerField< logPrimarySpeciesConcentration >( getName() ).
+ reference().resizeDimension< 1 >( m_numPrimarySpecies );
+
+ subRegion.registerField< logPrimarySpeciesConcentration_n >( getName() ).
+ reference().resizeDimension< 1 >( m_numPrimarySpecies );
+
+ subRegion.registerField< primarySpeciesAggregateMole >( getName() ).
+ reference().resizeDimension< 1 >( m_numPrimarySpecies );
+
+ subRegion.registerField< primarySpeciesAggregateMole_n >( getName() ).
+ reference().resizeDimension< 1 >( m_numPrimarySpecies );
+
+ subRegion.registerField< bcLogPrimarySpeciesConcentration >( getName() ).
+ reference().resizeDimension< 1 >( m_numPrimarySpecies );
+
+ subRegion.registerField< kineticReactionMolarIncrements >( getName() ).
+ reference().resizeDimension< 1 >( m_numKineticReactions );
+
+ subRegion.registerField< surfaceArea >( getName() ).
+ reference().resizeDimension< 1 >( m_numKineticReactions );
+
+ subRegion.registerField< initialSurfaceArea >( getName() ).
+ reference().resizeDimension< 1 >( m_numKineticReactions );
+ } );
+ } );
+}
+
+void SinglePhaseReactiveTransport::validateConstitutiveModels( DomainPartition & domain ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ SinglePhaseBase::validateConstitutiveModels( domain );
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions( regionNames, [&]( localIndex const,
+ ElementSubRegionBase & subRegion )
+ {
+ string const & porosityModelName = getConstitutiveName< PorosityBase >( subRegion );
+
+ PorosityBase const & porosity = getConstitutiveModel< PorosityBase >( subRegion, porosityModelName );
+
+ GEOS_THROW_IF( m_isUpdateReactivePorosity && (porosity.getCatalogName() != "ReactivePorosity"),
+ GEOS_FMT( "SinglePhaseReactiveTransport {}: the reaction porosity update option is enabled in the solver, but the porosity model {} is not for reactive porosity",
+ getDataContext(), porosity.getDataContext() ),
+ InputError );
+
+ if( m_isUpdateReactivePorosity )
+ {
+ ReactivePorosity const & reactivePorosity = getConstitutiveModel< ReactivePorosity >( subRegion, porosityModelName );
+
+ GEOS_THROW_IF_NE_MSG( reactivePorosity.numKineticReactions(), m_numKineticReactions,
+ GEOS_FMT( "Mismatch in number of kinetic reactions, check the number of components input in porosity model {}",
+ reactivePorosity.getDataContext() ),
+ InputError );
+ }
+ } );
+ } );
+}
+
+void SinglePhaseReactiveTransport::setupDofs( DomainPartition const & domain,
+ DofManager & dofManager ) const
+{
+ // add a field for the cell-centered degrees of freedom
+ dofManager.addField( viewKeyStruct::elemDofFieldString(),
+ FieldLocation::Elem,
+ m_numDofPerCell,
+ getMeshTargets() );
+
+ NumericalMethodsManager const & numericalMethodManager = domain.getNumericalMethodManager();
+ FiniteVolumeManager const & fvManager = numericalMethodManager.getFiniteVolumeManager();
+ FluxApproximationBase const & fluxApprox = fvManager.getFluxApproximation( m_discretizationName );
+
+ dofManager.addCoupling( viewKeyStruct::elemDofFieldString(), fluxApprox );
+}
+
+void SinglePhaseReactiveTransport::resetStateToBeginningOfStep( DomainPartition & domain )
+{
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const,
+ auto & subRegion )
+ {
+ arrayView2d< real64, compflow::USD_COMP > const logPrimarySpeciesConc = subRegion.template getField< fields::flow::logPrimarySpeciesConcentration >();
+ arrayView2d< real64 const, compflow::USD_COMP > const logPrimarySpeciesConc_n = subRegion.template getField< fields::flow::logPrimarySpeciesConcentration_n >();
+ logPrimarySpeciesConc.setValues< parallelDevicePolicy<> >( logPrimarySpeciesConc_n );
+ } );
+ } );
+
+ SinglePhaseBase::resetStateToBeginningOfStep( domain );
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const,
+ auto & subRegion )
+ {
+ updateMixedReactionSystem( subRegion );
+ updateSpeciesAmount( subRegion );
+ } );
+ } );
+}
+
+void SinglePhaseReactiveTransport::implicitStepSetup( real64 const & time_n,
+ real64 const & dt,
+ DomainPartition & domain )
+{
+ GEOS_MARK_FUNCTION;
+
+ SinglePhaseBase::implicitStepSetup( time_n, dt, domain );
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const,
+ auto & subRegion )
+ {
+ updateMixedReactionSystem( subRegion );
+ updateSpeciesAmount( subRegion );
+ } );
+ } );
+}
+
+void SinglePhaseReactiveTransport::implicitStepComplete( real64 const & time,
+ real64 const & dt,
+ DomainPartition & domain )
+{
+ GEOS_MARK_FUNCTION;
+
+ SinglePhaseBase::implicitStepComplete( time, dt, domain );
+
+ // Update molar increments of kinetic reactions for porosity update
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions( regionNames, [&]( localIndex const,
+ ElementSubRegionBase & subRegion )
+ {
+ updateKineticReactionMolarIncrements( dt, subRegion );
+ } );
+ } );
+
+ if( m_hasDiffusion )
+ {
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions( regionNames,
+ [&]( localIndex const,
+ ElementSubRegionBase & subRegion )
+ {
+ string const & diffusionName = subRegion.getReference< string >( viewKeyStruct::diffusionNamesString() );
+ DiffusionBase const & diffusionMaterial = getConstitutiveModel< DiffusionBase >( subRegion, diffusionName );
+ arrayView1d< real64 const > const temperature = subRegion.template getField< fields::flow::temperature >();
+ diffusionMaterial.saveConvergedTemperatureState( temperature );
+ } );
+ } );
+ }
+}
+
+void SinglePhaseReactiveTransport::assembleSystem( real64 const GEOS_UNUSED_PARAM( time_n ),
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+
+ assembleAccumulationTermsInMassBalanceAndSpeciesAmountEqs( dt,
+ domain,
+ dofManager,
+ localMatrix,
+ localRhs );
+ assembleFluxTerms( dt,
+ domain,
+ dofManager,
+ localMatrix,
+ localRhs );
+}
+
+void SinglePhaseReactiveTransport::assembleAccumulationTermsInMassBalanceAndSpeciesAmountEqs( real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions( regionNames,
+ [&]( localIndex const,
+ ElementSubRegionBase const & subRegion )
+ {
+ geos::constitutive::CoupledSolidBase const & solid =
+ getConstitutiveModel< geos::constitutive::CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) );
+
+ string const dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() );
+
+ if( m_isThermal )
+ {
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid const & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >( subRegion, subRegion.template getReference< string >( viewKeyStruct::fluidNamesString() ) );
+
+ thermalSinglePhaseReactiveBaseKernels::
+ AccumulationKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numPrimarySpecies,
+ dt,
+ dofManager.rankOffset(),
+ dofKey,
+ subRegion,
+ fluid,
+ solid,
+ localMatrix,
+ localRhs );
+ }
+ else
+ {
+ reactivefluid::ReactiveCompressibleSinglePhaseFluid const & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( subRegion, subRegion.template getReference< string >( viewKeyStruct::fluidNamesString() ) );
+
+ singlePhaseReactiveBaseKernels::
+ AccumulationKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numPrimarySpecies,
+ dt,
+ dofManager.rankOffset(),
+ dofKey,
+ subRegion,
+ fluid,
+ solid,
+ localMatrix,
+ localRhs );
+ }
+ } );
+ } );
+}
+
+void SinglePhaseReactiveTransport::assembleFluxTerms( real64 const dt,
+ DomainPartition const & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+ array1d< integer > mobilePrimarySpeciesFlags;
+ mobilePrimarySpeciesFlags.resize( m_numPrimarySpecies );
+
+ for( integer i=0; i 0 )
+ {
+ for( integer i = 0; i < m_immobilePrimarySpeciesIndices.size(); ++i )
+ {
+ localIndex const immobileSpeciesIndex = m_immobilePrimarySpeciesIndices[i];
+ mobilePrimarySpeciesFlags[immobileSpeciesIndex] = 0;
+ }
+ }
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel const & mesh,
+ string_array const & )
+ {
+ NumericalMethodsManager const & numericalMethodManager = domain.getNumericalMethodManager();
+ FiniteVolumeManager const & fvManager = numericalMethodManager.getFiniteVolumeManager();
+ FluxApproximationBase const & fluxApprox = fvManager.getFluxApproximation( m_discretizationName );
+
+ string const & dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() );
+
+ fluxApprox.forAllStencils( mesh, [&] ( auto & stencil )
+ {
+ typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper();
+
+ if( m_isThermal )
+ {
+ thermalSinglePhaseReactiveFVMKernels::
+ FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( m_numPrimarySpecies,
+ m_hasDiffusion,
+ mobilePrimarySpeciesFlags.toViewConst(),
+ dofManager.rankOffset(),
+ dofKey,
+ getName(),
+ mesh.getElemManager(),
+ stencilWrapper,
+ dt,
+ localMatrix.toViewConstSizes(),
+ localRhs.toView() );
+ }
+ else
+ {
+ singlePhaseReactiveFVMKernels::
+ FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( m_numPrimarySpecies,
+ m_hasDiffusion,
+ mobilePrimarySpeciesFlags.toViewConst(),
+ dofManager.rankOffset(),
+ dofKey,
+ getName(),
+ mesh.getElemManager(),
+ stencilWrapper,
+ dt,
+ localMatrix.toViewConstSizes(),
+ localRhs.toView() );
+ }
+ } );
+ } );
+}
+
+void SinglePhaseReactiveTransport::updateState( DomainPartition & domain )
+{
+ GEOS_MARK_FUNCTION;
+
+ SinglePhaseBase::updateState( domain );
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const,
+ auto & subRegion )
+ {
+ updateMixedReactionSystem( subRegion );
+
+ updateSpeciesAmount( subRegion );
+ } );
+ } );
+}
+
+void SinglePhaseReactiveTransport::updateSpeciesAmount( ElementSubRegionBase & subRegion ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ arrayView2d< real64, compflow::USD_COMP > const primarySpeciesAggregateMole = subRegion.getField< fields::flow::primarySpeciesAggregateMole >();
+ arrayView2d< real64, compflow::USD_COMP > const primarySpeciesAggregateMole_n = subRegion.getField< fields::flow::primarySpeciesAggregateMole_n >();
+
+ CoupledSolidBase const & porousSolid =
+ getConstitutiveModel< CoupledSolidBase >( subRegion, subRegion.template getReference< string >( viewKeyStruct::solidNamesString() ) );
+ arrayView2d< real64 const > const porosity = porousSolid.getPorosity();
+ arrayView2d< real64 const > const porosity_n = porousSolid.getPorosity_n();
+
+ arrayView1d< real64 const > const volume = subRegion.getElementVolume();
+ arrayView1d< real64 > const deltaVolume = subRegion.getField< fields::flow::deltaVolume >();
+
+ if( m_isThermal )
+ {
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const primarySpeciesAggregateConcentration = fluid.primarySpeciesAggregateConcentration();
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const primarySpeciesAggregateConcentration_n = fluid.primarySpeciesAggregateConcentration_n();
+
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ {
+ for( integer is = 0; is < m_numPrimarySpecies; ++is )
+ {
+ primarySpeciesAggregateMole[ei][is] = porosity[ei][0] * ( volume[ei] + deltaVolume[ei] ) * primarySpeciesAggregateConcentration[ei][0][is];
+
+ if( isZero( primarySpeciesAggregateMole_n[ei][is] ) )
+ primarySpeciesAggregateMole_n[ei][is] = porosity_n[ei][0] * volume[ei] * primarySpeciesAggregateConcentration_n[ei][0][is];
+ }
+ } );
+ }
+ else
+ {
+ reactivefluid::ReactiveCompressibleSinglePhaseFluid & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const primarySpeciesAggregateConcentration = fluid.primarySpeciesAggregateConcentration();
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const primarySpeciesAggregateConcentration_n = fluid.primarySpeciesAggregateConcentration_n();
+
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ {
+ for( integer is = 0; is < m_numPrimarySpecies; ++is )
+ {
+ primarySpeciesAggregateMole[ei][is] = porosity[ei][0] * ( volume[ei] + deltaVolume[ei] ) * primarySpeciesAggregateConcentration[ei][0][is];
+
+ if( isZero( primarySpeciesAggregateMole_n[ei][is] ) )
+ primarySpeciesAggregateMole_n[ei][is] = porosity_n[ei][0] * volume[ei] * primarySpeciesAggregateConcentration_n[ei][0][is];
+ }
+ } );
+ }
+}
+
+void SinglePhaseReactiveTransport::updateKineticReactionMolarIncrements( real64 const dt,
+ ElementSubRegionBase & subRegion ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ arrayView2d< real64, compflow::USD_COMP > const kineticReactionMolarIncrements = subRegion.getField< fields::flow::kineticReactionMolarIncrements >();
+ if( m_isThermal )
+ {
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const kineticReactionRates = fluid.kineticReactionRates();
+
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ {
+ for( integer r = 0; r < m_numKineticReactions; ++r )
+ {
+ kineticReactionMolarIncrements[ei][r] = dt* kineticReactionRates[ei][0][r];
+ }
+ } );
+ }
+ else
+ {
+ reactivefluid::ReactiveCompressibleSinglePhaseFluid & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const kineticReactionRates = fluid.kineticReactionRates();
+
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ {
+ for( integer r = 0; r < m_numKineticReactions; ++r )
+ {
+ kineticReactionMolarIncrements[ei][r] = dt* kineticReactionRates[ei][0][r];
+ }
+ } );
+ }
+}
+
+void SinglePhaseReactiveTransport::updateFluidModel( ObjectManagerBase & dataGroup ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ arrayView1d< real64 const > const pres = dataGroup.getField< fields::flow::pressure >();
+ arrayView1d< real64 const > const temp = dataGroup.getField< fields::flow::temperature >();
+ arrayView2d< real64 const, compflow::USD_COMP > const logPrimaryConc = dataGroup.getField< fields::flow::logPrimarySpeciesConcentration >();
+
+ if( m_isThermal )
+ {
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >( dataGroup, dataGroup.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+
+ constitutive::constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid )
+ {
+ typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
+ singlePhaseReactiveBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp, logPrimaryConc );
+ } );
+ }
+ else
+ {
+ reactivefluid::ReactiveCompressibleSinglePhaseFluid & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( dataGroup, dataGroup.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+
+ constitutive::constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid )
+ {
+ typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
+ singlePhaseReactiveBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp, logPrimaryConc );
+ } );
+ }
+}
+
+void SinglePhaseReactiveTransport::updatePorosityAndPermeability( CellElementSubRegion & subRegion ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ if( m_isUpdateReactivePorosity )
+ {
+ arrayView1d< real64 const > const & pressure = subRegion.getField< fields::flow::pressure >();
+ arrayView1d< real64 const > const & temperature = subRegion.getField< fields::flow::temperature >();
+ arrayView2d< real64 const, compflow::USD_COMP > const kineticReactionMolarIncrements = subRegion.getField< fields::flow::kineticReactionMolarIncrements >();
+
+ string const & solidName = subRegion.getReference< string >( viewKeyStruct::solidNamesString() );
+ CoupledSolidBase & porousSolid = subRegion.template getConstitutiveModel< CoupledSolidBase >( solidName );
+
+ constitutive::ConstitutivePassThru< CoupledSolidBase >::execute( porousSolid, [=, &subRegion] ( auto & castedPorousSolid )
+ {
+ typename TYPEOFREF( castedPorousSolid ) ::KernelWrapper porousWrapper = castedPorousSolid.createKernelUpdates();
+ updatePorosityAndPermeabilityFromPressureTemperatureAndReactions( porousWrapper, subRegion, pressure, temperature, kineticReactionMolarIncrements );
+ } );
+ }
+ else
+ {
+ FlowSolverBase::updatePorosityAndPermeability( subRegion );
+ }
+}
+
+void SinglePhaseReactiveTransport::updateMixedReactionSystem( ElementSubRegionBase & subRegion ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ updateSurfaceArea( subRegion );
+
+ arrayView1d< real64 const > const pres = subRegion.getField< fields::flow::pressure >();
+ arrayView1d< real64 const > const temp = subRegion.getField< fields::flow::temperature >();
+ arrayView2d< real64 const, compflow::USD_COMP > const logPrimaryConc = subRegion.getField< fields::flow::logPrimarySpeciesConcentration >();
+ arrayView2d< real64 const, compflow::USD_COMP > const surfaceArea = subRegion.getField< fields::flow::surfaceArea >();
+
+ if( m_isThermal )
+ {
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+
+ constitutive::constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid )
+ {
+ singlePhaseReactiveBaseKernels::MixedSystemReactionUpdateKernel::launch( castedFluid, pres, temp, logPrimaryConc, surfaceArea );
+ } );
+ }
+ else
+ {
+ reactivefluid::ReactiveCompressibleSinglePhaseFluid & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+
+ constitutive::constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid )
+ {
+ singlePhaseReactiveBaseKernels::MixedSystemReactionUpdateKernel::launch( castedFluid, pres, temp, logPrimaryConc, surfaceArea );
+ } );
+ }
+}
+
+void SinglePhaseReactiveTransport::updateSurfaceArea( ElementSubRegionBase & subRegion ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ arrayView2d< real64 const, compflow::USD_COMP > const initialSurfaceArea = subRegion.getField< fields::flow::initialSurfaceArea >();
+ arrayView2d< real64, compflow::USD_COMP > const surfaceArea = subRegion.getField< fields::flow::surfaceArea >();
+
+ if( m_isUpdateReactivePorosity && m_isUpdateSurfaceArea )
+ {
+ string const & solidName = subRegion.getReference< string >( viewKeyStruct::solidNamesString() );
+ CoupledSolidBase & porousSolid = subRegion.template getConstitutiveModel< CoupledSolidBase >( solidName );
+
+ constitutive::ConstitutivePassThru< CoupledSolidBase >::execute( porousSolid, [=, &subRegion] ( auto & castedPorousSolid )
+ {
+ typename TYPEOFREF( castedPorousSolid ) ::KernelWrapper porousWrapper = castedPorousSolid.createKernelUpdates();
+ updateSurfaceAreaFromReactions( porousWrapper, subRegion, initialSurfaceArea, surfaceArea );
+ } );
+ }
+ else
+ {
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ {
+ for( integer ir = 0; ir < m_numKineticReactions; ++ir )
+ {
+ surfaceArea[ei][ir] = initialSurfaceArea[ei][ir];
+ }
+ } );
+ }
+}
+
+void SinglePhaseReactiveTransport::initializeFluidState( MeshLevel & mesh, string_array const & regionNames )
+{
+ mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const,
+ auto & subRegion )
+ {
+ string const & fluidName = subRegion.template getReference< string >( viewKeyStruct::fluidNamesString() );
+ updateFluidState( subRegion );
+
+ // 2. save the initial density (for use in the single-phase poromechanics solver to compute the deltaBodyForce)
+ if( m_isThermal )
+ {
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid const & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >( subRegion, fluidName );
+
+ fluid.initializeState();
+ }
+ else
+ {
+ reactivefluid::ReactiveCompressibleSinglePhaseFluid const & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( subRegion, fluidName );
+
+ fluid.initializeState();
+ }
+
+ initializeEquilibriumReaction( subRegion );
+
+ updateMixedReactionSystem( subRegion );
+
+ SinglePhaseBase::updateMass( subRegion );
+ updateSpeciesAmount( subRegion );
+
+ saveConvergedState( subRegion );
+
+ // If the diffusion is supported, initialize the model
+ if( m_hasDiffusion )
+ {
+ string const & diffusionName = subRegion.template getReference< string >( viewKeyStruct::diffusionNamesString() );
+ DiffusionBase const & diffusionMaterial = getConstitutiveModel< DiffusionBase >( subRegion, diffusionName );
+ arrayView1d< real64 const > const temperature = subRegion.template getField< fields::flow::temperature >();
+ diffusionMaterial.initializeTemperatureState( temperature );
+ }
+ } );
+}
+
+void SinglePhaseReactiveTransport::initializeEquilibriumReaction( ElementSubRegionBase & subRegion ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ arrayView1d< real64 const > const pres = subRegion.getField< fields::flow::pressure >();
+ arrayView1d< real64 const > const temp = subRegion.getField< fields::flow::temperature >();
+ arrayView2d< real64, compflow::USD_COMP > const logPrimaryConc = subRegion.getField< fields::flow::logPrimarySpeciesConcentration >();
+
+ if( m_isThermal )
+ {
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+
+ constitutive::constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid )
+ {
+ singlePhaseReactiveBaseKernels::EquilibriumReactionUpdateKernel::launch( castedFluid, pres, temp, logPrimaryConc );
+ } );
+
+ fluid.saveConvergedState();
+ }
+ else
+ {
+ reactivefluid::ReactiveCompressibleSinglePhaseFluid & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+
+ constitutive::constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid )
+ {
+ singlePhaseReactiveBaseKernels::EquilibriumReactionUpdateKernel::launch( castedFluid, pres, temp, logPrimaryConc );
+ } );
+
+ fluid.saveConvergedState();
+ }
+}
+
+void SinglePhaseReactiveTransport::initializePostInitialConditionsPreSubGroups()
+{
+ GEOS_MARK_FUNCTION;
+
+ FlowSolverBase::initializePostInitialConditionsPreSubGroups();
+
+ DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" );
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ FieldIdentifiers fieldsToBeSync;
+ fieldsToBeSync.addElementFields( { fields::flow::logPrimarySpeciesConcentration::key() },
+ regionNames );
+
+ CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, mesh, domain.getNeighbors(), false );
+ } );
+
+ FlowSolverBase::initializeState( domain );
+}
+
+namespace
+{
+char const bcLogMessage[] =
+ "SinglePhaseReactiveTransport {}: at time {}s, "
+ "the <{}> boundary condition '{}' is applied to the element set '{}' in subRegion '{}'. "
+ "\nThe scale of this boundary condition is {} and multiplies the value of the provided function (if any). "
+ "\nThe total number of target elements (including ghost elements) is {}. "
+ "\nNote that if this number is equal to zero for all subRegions, the boundary condition will not be applied on this element set.";
+}
+
+void SinglePhaseReactiveTransport::applyBoundaryConditions( real64 const time_n,
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+
+ // apply Dirichlet boundary conditions.
+ applyDirichletBC( time_n, dt, domain, dofManager, localMatrix.toViewConstSizes(), localRhs.toView() );
+
+ // apply flux boundary conditions
+ applySourceFluxBC( time_n, dt, domain, dofManager, localMatrix.toViewConstSizes(), localRhs.toView() );
+
+ // apply face Dirichlet boundary conditions.
+ applyFaceDirichletBC( time_n, dt, dofManager, domain, localMatrix, localRhs );
+}
+
+void SinglePhaseReactiveTransport::applySourceFluxBC( real64 const time_n,
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance();
+
+ string const dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() );
+
+ // Step 1: count individual source flux boundary conditions
+
+ stdMap< string, localIndex > bcNameToBcId;
+ localIndex bcCounter = 0;
+
+ fsManager.forSubGroups< SourceFluxBoundaryCondition >( [&] ( SourceFluxBoundaryCondition const & bc )
+ {
+ // collect all the bc names to idx
+ bcNameToBcId[bc.getName()] = bcCounter;
+ bcCounter++;
+ } );
+
+ if( bcCounter == 0 )
+ {
+ return;
+ }
+
+ // Step 2: count the set size for each source flux (each source flux may have multiple target sets)
+
+ array1d< globalIndex > bcAllSetsSize( bcNameToBcId.size() );
+
+ computeSourceFluxSizeScalingFactor( time_n,
+ dt,
+ domain,
+ bcNameToBcId,
+ bcAllSetsSize.toView() );
+
+ // Step 3: we are ready to impose the boundary condition, normalized by the set size
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & )
+ {
+ integer const isThermal = m_isThermal;
+ integer const numPrimarySpecies = m_numPrimarySpecies;
+
+ fsManager.apply< ElementSubRegionBase,
+ SourceFluxBoundaryCondition >( time_n + dt,
+ mesh,
+ SourceFluxBoundaryCondition::catalogName(),
+ [&, isThermal, numPrimarySpecies]( SourceFluxBoundaryCondition const & fs,
+ string const & setName,
+ SortedArrayView< localIndex const > const & targetSet,
+ ElementSubRegionBase & subRegion,
+ string const & )
+ {
+ if( m_nonlinearSolverParameters.m_numNewtonIterations == 0 )
+ {
+ globalIndex const numTargetElems = MpiWrapper::sum< globalIndex >( targetSet.size() );
+ GEOS_LOG_LEVEL_RANK_0_ON_GROUP( logInfo::BoundaryConditions,
+ GEOS_FMT( bcLogMessage,
+ getName(), time_n+dt, fs.getCatalogName(), fs.getName(),
+ setName, subRegion.getName(), fs.getScale(), numTargetElems ),
+ fs );
+ }
+
+ if( targetSet.size() == 0 )
+ {
+ return;
+ }
+ if( !subRegion.hasWrapper( dofKey ) )
+ {
+ GEOS_LOG_LEVEL_BY_RANK_ON_GROUP( logInfo::BoundaryConditions,
+ GEOS_FMT( "{}: trying to apply {}, but its targetSet named '{}' intersects with non-simulated region named '{}'.",
+ getDataContext(), SourceFluxBoundaryCondition::catalogName(), setName, subRegion.getName() ),
+ fs );
+ return;
+ }
+
+ arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey );
+ arrayView1d< integer const > const ghostRank = subRegion.ghostRank();
+
+ // Step 3.1: get the values of the source boundary condition that need to be added to the rhs
+
+ array1d< globalIndex > dofArray( targetSet.size() );
+ array1d< real64 > rhsContributionArray( targetSet.size() );
+ arrayView1d< real64 > rhsContributionArrayView = rhsContributionArray.toView();
+ localIndex const rankOffset = dofManager.rankOffset();
+
+ RAJA::ReduceSum< parallelDeviceReduce, real64 > massProd( 0.0 );
+
+ // note that the dofArray will not be used after this step (simpler to use dofNumber instead)
+ fs.computeRhsContribution< FieldSpecificationAdd,
+ parallelDevicePolicy<> >( targetSet.toViewConst(),
+ time_n + dt,
+ dt,
+ subRegion,
+ dofNumber,
+ rankOffset,
+ localMatrix,
+ dofArray.toView(),
+ rhsContributionArrayView,
+ [] GEOS_HOST_DEVICE ( localIndex const )
+ {
+ return 0.0;
+ } );
+
+ // Step 3.2: we are ready to add the right-hand side contributions, taking into account our equation layout
+
+ // get the normalizer
+ real64 const sizeScalingFactor = bcAllSetsSize[bcNameToBcId.at( fs.getName())];
+
+ if( isThermal )
+ {
+ using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< 1 >;
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid const & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >( subRegion, subRegion.template getReference< string >( viewKeyStruct::fluidNamesString() ) );
+
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const primarySpeciesAggregateConcentration = fluid.primarySpeciesAggregateConcentration();
+ arrayView4d< real64 const,
+ reactivefluid::USD_SPECIES_DC > const dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations =
+ fluid.dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations();
+ arrayView2d< real64 const, singlefluid::USD_FLUID > const density = fluid.density();
+ arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > const dDensity = fluid.dDensity();
+ arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const enthalpy = fluid.enthalpy();
+ arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > const dEnthalpy = fluid.dEnthalpy();
+
+ forAll< parallelDevicePolicy<> >( targetSet.size(), [sizeScalingFactor,
+ targetSet,
+ rankOffset,
+ ghostRank,
+ dofNumber,
+ numPrimarySpecies,
+ primarySpeciesAggregateConcentration,
+ dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ density,
+ dDensity,
+ enthalpy,
+ dEnthalpy,
+ rhsContributionArrayView,
+ localRhs,
+ localMatrix,
+ massProd] GEOS_HOST_DEVICE ( localIndex const a )
+ {
+ singlePhaseReactiveBaseKernels::internal::kernelLaunchSelectorCompSwitch( numPrimarySpecies, [&] ( auto NS )
+ {
+ integer constexpr NUM_SPECIES = NS();
+
+ // we need to filter out ghosts here, because targetSet may contain them
+ localIndex const ei = targetSet[a];
+ if( ghostRank[ei] >= 0 )
+ {
+ return;
+ }
+
+ // add the value to the mass balance equation
+ globalIndex const massRowIndex = dofNumber[ei] - rankOffset;
+ globalIndex const energyRowIndex = massRowIndex + 1;
+ globalIndex const speciesRowBeginIndex = massRowIndex + 2;
+ real64 const rhsValue = rhsContributionArrayView[a] / sizeScalingFactor; // scale the contribution by the sizeScalingFactor
+ // here!
+ localRhs[massRowIndex] += rhsValue;
+ massProd += rhsValue;
+
+ // add the value to the energy balance equation and species mass balance equations if the flux is positive (i.e., it's a
+ // producer)
+ if( rhsContributionArrayView[a] > 0.0 )
+ {
+ globalIndex const pressureDofIndex = dofNumber[ei] - rankOffset;
+ globalIndex const temperatureDofIndex = pressureDofIndex + 1;
+
+ globalIndex dofIndices[2+NUM_SPECIES]{};
+
+ dofIndices[0] = pressureDofIndex;
+ dofIndices[1] = temperatureDofIndex;
+
+ for( integer i = 0; i < NUM_SPECIES; ++i )
+ {
+ dofIndices[i+2] = pressureDofIndex + i + 2;
+ }
+
+ // add the value to the energy balance equation
+ localRhs[energyRowIndex] += enthalpy[ei][0] * rhsValue;
+
+ real64 jacobianEnergyFlux[2+NUM_SPECIES]{0.0};
+
+ jacobianEnergyFlux[0] = rhsValue * dEnthalpy[ei][0][DerivOffset::dP];
+ jacobianEnergyFlux[1] = rhsValue * dEnthalpy[ei][0][DerivOffset::dT];
+
+ localMatrix.template addToRow< serialAtomic >( energyRowIndex,
+ dofIndices,
+ jacobianEnergyFlux,
+ 2+NUM_SPECIES );
+
+ // add the value to the species mass balance equations
+ for( integer i = 0; i < NUM_SPECIES; ++i )
+ {
+ localRhs[speciesRowBeginIndex + i] += primarySpeciesAggregateConcentration[ei][0][i] / density[ei][0] * rhsValue;
+
+ real64 jacobianSpeciesFlux[2+NUM_SPECIES] = {0.0};
+ jacobianSpeciesFlux[0] += -primarySpeciesAggregateConcentration[ei][0][i] * dDensity[ei][0][DerivOffset::dP] / (density[ei][0] * density[ei][0]) * rhsValue;
+ jacobianSpeciesFlux[1] += -primarySpeciesAggregateConcentration[ei][0][i] * dDensity[ei][0][DerivOffset::dT] / (density[ei][0] * density[ei][0]) * rhsValue;
+
+ for( integer j = 0; j < NUM_SPECIES; ++j )
+ {
+ jacobianSpeciesFlux[j+2] += dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations[ei][0][i][j] / density[ei][0] * rhsValue;
+ }
+
+ localMatrix.template addToRow< serialAtomic >( speciesRowBeginIndex + i,
+ dofIndices,
+ jacobianSpeciesFlux,
+ 2+NUM_SPECIES );
+ }
+ }
+ } );
+ } );
+ }
+ else
+ {
+ using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< 1 >;
+ reactivefluid::ReactiveCompressibleSinglePhaseFluid const & fluid =
+ getConstitutiveModel< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( subRegion, subRegion.template getReference< string >( viewKeyStruct::fluidNamesString() ) );
+
+ arrayView3d< real64 const, reactivefluid::USD_SPECIES > const primarySpeciesAggregateConcentration = fluid.primarySpeciesAggregateConcentration();
+ arrayView4d< real64 const,
+ reactivefluid::USD_SPECIES_DC > const dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations =
+ fluid.dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations();
+ arrayView2d< real64 const, singlefluid::USD_FLUID > const density = fluid.density();
+ arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > const dDensity = fluid.dDensity();
+
+ forAll< parallelDevicePolicy<> >( targetSet.size(), [sizeScalingFactor,
+ targetSet,
+ rankOffset,
+ ghostRank,
+ dofNumber,
+ numPrimarySpecies,
+ primarySpeciesAggregateConcentration,
+ dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations,
+ density,
+ dDensity,
+ rhsContributionArrayView,
+ localRhs,
+ localMatrix,
+ massProd] GEOS_HOST_DEVICE ( localIndex const a )
+ {
+ singlePhaseReactiveBaseKernels::internal::kernelLaunchSelectorCompSwitch( numPrimarySpecies, [&] ( auto NS )
+ {
+ integer constexpr NUM_SPECIES = NS();
+
+ // we need to filter out ghosts here, because targetSet may contain them
+ localIndex const ei = targetSet[a];
+ if( ghostRank[ei] >= 0 )
+ {
+ return;
+ }
+
+ // add the value to the mass balance equation
+ globalIndex const massRowIndex = dofNumber[ei] - rankOffset;
+ globalIndex const speciesRowBeginIndex = massRowIndex + 1;
+ real64 const rhsValue = rhsContributionArrayView[a] / sizeScalingFactor; // scale the contribution by the sizeScalingFactor
+ // here!
+ localRhs[massRowIndex] += rhsValue;
+ massProd += rhsValue;
+
+ //add the value to the species mass balance equations if the flux is positive (i.e., it's a producer)
+ if( rhsContributionArrayView[a] > 0.0 )
+ {
+ globalIndex const pressureDofIndex = dofNumber[ei] - rankOffset;
+
+ globalIndex dofIndices[1+NUM_SPECIES]{};
+
+ dofIndices[0] = pressureDofIndex;
+
+ for( integer i = 0; i < NUM_SPECIES; ++i )
+ {
+ dofIndices[i+1] = pressureDofIndex + i + 1;
+ }
+
+ for( integer i = 0; i < NUM_SPECIES; ++i )
+ {
+ localRhs[speciesRowBeginIndex + i] += primarySpeciesAggregateConcentration[ei][0][i] / density[ei][0] * rhsValue;
+
+ real64 jacobian[1+NUM_SPECIES] = {0.0};
+ jacobian[0] += -primarySpeciesAggregateConcentration[ei][0][i] * dDensity[ei][0][DerivOffset::dP] / (density[ei][0] * density[ei][0]) * rhsValue;
+
+ for( integer j = 0; j < NUM_SPECIES; ++j )
+ {
+ jacobian[j+1] += dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations[ei][0][i][j] / density[ei][0] * rhsValue;
+ }
+
+ localMatrix.template addToRow< serialAtomic >( speciesRowBeginIndex + i,
+ dofIndices,
+ jacobian,
+ 1+NUM_SPECIES );
+ }
+ }
+ } );
+ } );
+ }
+
+ SourceFluxStatsAggregator::forAllFluxStatWrappers( subRegion, fs.getName(),
+ [&]( SourceFluxStatsAggregator::WrappedStats & wrapper )
+ {
+ // set the new sub-region statistics for this timestep
+ array1d< real64 > massProdArr{ 1 };
+ massProdArr[0] = massProd.get();
+ wrapper.gatherTimeStepStats( time_n, dt, massProdArr.toViewConst(), targetSet.size() );
+ } );
+ } );
+ } );
+}
+
+void SinglePhaseReactiveTransport::applyDirichletBC( real64 const time_n,
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) const
+{
+ FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance();
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & )
+ {
+ // 1. Apply pressure Dirichlet BCs, store in a separate field
+ applyFieldValue< ElementSubRegionBase >( time_n, dt, mesh, bcLogMessage,
+ fields::flow::pressure::key(), fields::flow::bcPressure::key() );
+ // 2. Apply primary species BC (log promary species concentration)
+ applyFieldValue< ElementSubRegionBase >( time_n, dt, mesh, bcLogMessage,
+ fields::flow::logPrimarySpeciesConcentration::key(), fields::flow::bcLogPrimarySpeciesConcentration::key() );
+ // 3. Apply temperature Dirichlet BCs, store in a separate field
+ if( m_isThermal )
+ {
+ applyFieldValue< ElementSubRegionBase >( time_n, dt, mesh, bcLogMessage,
+ fields::flow::temperature::key(), fields::flow::bcTemperature::key() );
+ }
+
+ globalIndex const rankOffset = dofManager.rankOffset();
+ string const dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() );
+
+ // 4. Apply pressure to the system
+ fsManager.apply< ElementSubRegionBase >( time_n + dt,
+ mesh,
+ fields::flow::pressure::key(),
+ [&] ( FieldSpecificationBase const &,
+ string const &,
+ SortedArrayView< localIndex const > const & targetSet,
+ ElementSubRegionBase & subRegion,
+ string const & )
+ {
+ arrayView1d< integer const > const ghostRank = subRegion.ghostRank();
+ arrayView1d< globalIndex const > const dofNumber =
+ subRegion.getReference< array1d< globalIndex > >( dofKey );
+
+ arrayView1d< real64 const > const bcPres =
+ subRegion.getReference< array1d< real64 > >( fields::flow::bcPressure::key() );
+ arrayView1d< real64 const > const pres =
+ subRegion.getReference< array1d< real64 > >( fields::flow::pressure::key() );
+
+ forAll< parallelDevicePolicy<> >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a )
+ {
+ localIndex const ei = targetSet[a];
+ if( ghostRank[ei] >= 0 )
+ {
+ return;
+ }
+
+ globalIndex const dofIndex = dofNumber[ei];
+ localIndex const localRow = dofIndex - rankOffset;
+ real64 rhsValue;
+
+ // 4.1. Apply pressure value to the matrix/rhs
+ FieldSpecificationEqual::SpecifyFieldValue( dofIndex,
+ rankOffset,
+ localMatrix,
+ rhsValue,
+ bcPres[ei],
+ pres[ei] );
+ localRhs[localRow] = rhsValue;
+ } );
+ } );
+
+ // 5. Apply log primary species concentration to the system
+ fsManager.apply< ElementSubRegionBase >( time_n + dt,
+ mesh,
+ fields::flow::logPrimarySpeciesConcentration::key(),
+ [&] ( FieldSpecificationBase const &,
+ string const &,
+ SortedArrayView< localIndex const > const & targetSet,
+ ElementSubRegionBase & subRegion,
+ string const & )
+ {
+ arrayView1d< integer const > const ghostRank = subRegion.ghostRank();
+ arrayView1d< globalIndex const > const dofNumber =
+ subRegion.getReference< array1d< globalIndex > >( dofKey );
+
+ arrayView2d< real64 const, compflow::USD_COMP > const bcLogPrimaryConc =
+ subRegion.getReference< array2d< real64, compflow::LAYOUT_COMP > >( fields::flow::bcLogPrimarySpeciesConcentration::key() );
+ arrayView2d< real64 const, compflow::USD_COMP > const logPrimaryConc =
+ subRegion.getReference< array2d< real64, compflow::LAYOUT_COMP > >( fields::flow::logPrimarySpeciesConcentration::key() );
+
+ integer const numPrimarySpecies = m_numPrimarySpecies;
+ forAll< parallelDevicePolicy<> >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a )
+ {
+ localIndex const ei = targetSet[a];
+ if( ghostRank[ei] >= 0 )
+ {
+ return;
+ }
+
+ globalIndex const dofIndex = dofNumber[ei];
+ localIndex const localRow = dofIndex - rankOffset;
+ real64 rhsValue;
+
+ integer const speciesDofBeginIndex = m_isThermal? 2:1;
+
+ // 5.1. For each component, apply target global density value
+ for( integer is = 0; is < numPrimarySpecies; ++is )
+ {
+ FieldSpecificationEqual::SpecifyFieldValue( dofIndex + is + speciesDofBeginIndex,
+ rankOffset,
+ localMatrix,
+ rhsValue,
+ bcLogPrimaryConc[ei][is],
+ logPrimaryConc[ei][is] );
+ localRhs[localRow + is + speciesDofBeginIndex] = rhsValue;
+ }
+ } );
+ } );
+
+ // 6. Apply temperature to the system
+ if( m_isThermal )
+ {
+ fsManager.apply< ElementSubRegionBase >( time_n + dt,
+ mesh,
+ fields::flow::temperature::key(),
+ [&] ( FieldSpecificationBase const &,
+ string const &,
+ SortedArrayView< localIndex const > const & targetSet,
+ ElementSubRegionBase & subRegion,
+ string const & )
+ {
+ arrayView1d< integer const > const ghostRank =
+ subRegion.getReference< array1d< integer > >( ObjectManagerBase::viewKeyStruct::ghostRankString() );
+ arrayView1d< globalIndex const > const dofNumber =
+ subRegion.getReference< array1d< globalIndex > >( dofKey );
+ arrayView1d< real64 const > const bcTemp =
+ subRegion.getReference< array1d< real64 > >( fields::flow::bcTemperature::key() );
+ arrayView1d< real64 const > const temp =
+ subRegion.getReference< array1d< real64 > >( fields::flow::temperature::key() );
+
+ forAll< parallelDevicePolicy<> >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a )
+ {
+ localIndex const ei = targetSet[a];
+ if( ghostRank[ei] >= 0 )
+ {
+ return;
+ }
+
+ globalIndex const dofIndex = dofNumber[ei];
+ localIndex const localRow = dofIndex - rankOffset;
+ real64 rhsValue;
+
+ // 4.2. Apply temperature value to the matrix/rhs
+ FieldSpecificationEqual::SpecifyFieldValue( dofIndex + 1,
+ rankOffset,
+ localMatrix,
+ rhsValue,
+ bcTemp[ei],
+ temp[ei] );
+ localRhs[localRow + 1] = rhsValue;
+ } );
+ } );
+ }
+ } );
+}
+
+real64 SinglePhaseReactiveTransport::calculateResidualNorm( real64 const & GEOS_UNUSED_PARAM( time_n ),
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ DomainPartition const & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+
+ integer constexpr numNorm = 3; // total mass balance, energy balance, and species mass balance
+ array1d< real64 > localResidualNorm;
+ array1d< real64 > localResidualNormalizer;
+ localResidualNorm.resize( numNorm );
+ localResidualNormalizer.resize( numNorm );
+
+ physicsSolverBaseKernels::NormType const normType = SinglePhaseBase::getNonlinearSolverParameters().normType();
+
+ globalIndex const rankOffset = dofManager.rankOffset();
+ string const dofKey = dofManager.getKey( SinglePhaseBase::viewKeyStruct::elemDofFieldString() );
+
+ this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel const & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions( regionNames,
+ [&]( localIndex const,
+ ElementSubRegionBase const & subRegion )
+ {
+ real64 subRegionResidualNorm[numNorm]{};
+ real64 subRegionResidualNormalizer[numNorm]{};
+
+ // step 1: compute the norm in the subRegion
+
+ if( m_isThermal )
+ {
+ singlePhaseReactiveBaseKernels::
+ ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( normType,
+ m_numPrimarySpecies,
+ rankOffset,
+ dofKey,
+ localRhs,
+ subRegion,
+ m_nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm,
+ subRegionResidualNormalizer );
+ }
+ else
+ {
+ real64 subRegionFlowResidualNorm[2]{};
+ real64 subRegionFlowResidualNormalizer[2]{};
+
+ singlePhaseReactiveBaseKernels::
+ ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( normType,
+ m_numPrimarySpecies,
+ rankOffset,
+ dofKey,
+ localRhs,
+ subRegion,
+ m_nonlinearSolverParameters.m_minNormalizer,
+ subRegionFlowResidualNorm,
+ subRegionFlowResidualNormalizer );
+ subRegionResidualNorm[0] = subRegionFlowResidualNorm[0];
+ subRegionResidualNorm[1] = subRegionFlowResidualNorm[1];
+ subRegionResidualNormalizer[0] = subRegionFlowResidualNormalizer[0];
+ subRegionResidualNormalizer[1] = subRegionFlowResidualNormalizer[1];
+ }
+
+ // step 2: first reduction across meshBodies/regions/subRegions
+
+ if( normType == physicsSolverBaseKernels::NormType::Linf )
+ {
+ physicsSolverBaseKernels::LinfResidualNormHelper::
+ updateLocalNorm< numNorm >( subRegionResidualNorm, localResidualNorm );
+ }
+ else
+ {
+ physicsSolverBaseKernels::L2ResidualNormHelper::
+ updateLocalNorm< numNorm >( subRegionResidualNorm, subRegionResidualNormalizer, localResidualNorm, localResidualNormalizer );
+ }
+ } );
+ } );
+
+ // step 3: second reduction across MPI ranks
+
+ real64 residualNorm = 0.0;
+ array1d< real64 > globalResidualNorm;
+ globalResidualNorm.resize( numNorm );
+ if( m_isThermal )
+ {
+ if( normType == physicsSolverBaseKernels::NormType::Linf )
+ {
+ physicsSolverBaseKernels::LinfResidualNormHelper::
+ computeGlobalNorm( localResidualNorm, globalResidualNorm );
+ }
+ else
+ {
+ physicsSolverBaseKernels::L2ResidualNormHelper::
+ computeGlobalNorm( localResidualNorm, localResidualNormalizer, globalResidualNorm );
+ }
+ residualNorm = sqrt( globalResidualNorm[0] * globalResidualNorm[0] + globalResidualNorm[1] * globalResidualNorm[1] + globalResidualNorm[2] * globalResidualNorm[2] );
+
+ GEOS_LOG_LEVEL_RANK_0_NLR( logInfo::Convergence, GEOS_FMT( " ( RtotalMass RspeciesAmount ) = ( {:4.2e} {:4.2e} ) ( Renergy ) = ( {:4.2e} )",
+ globalResidualNorm[0], globalResidualNorm[2], globalResidualNorm[1] ));
+ }
+ else
+ {
+ if( normType == physicsSolverBaseKernels::NormType::Linf )
+ {
+ physicsSolverBaseKernels::LinfResidualNormHelper::
+ computeGlobalNorm( localResidualNorm, globalResidualNorm );
+ }
+ else
+ {
+ physicsSolverBaseKernels::L2ResidualNormHelper::
+ computeGlobalNorm( localResidualNorm, localResidualNormalizer, globalResidualNorm );
+ }
+ residualNorm = sqrt( globalResidualNorm[0] * globalResidualNorm[0] + globalResidualNorm[1] * globalResidualNorm[1] );
+
+ GEOS_LOG_LEVEL_RANK_0_NLR( logInfo::Convergence, GEOS_FMT( " ( RtotalMass RspeciesAmount ) = ( {:4.2e} {:4.2e} )",
+ globalResidualNorm[0], globalResidualNorm[1] ) );
+ }
+ return residualNorm;
+}
+
+void SinglePhaseReactiveTransport::applySystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain )
+{
+ GEOS_UNUSED_VAR( dt );
+
+ if( m_isThermal )
+ {
+ DofManager::CompMask pressureMask( m_numDofPerCell, 0, 1 );
+ DofManager::CompMask temperatureMask( m_numDofPerCell, 1, 2 );
+ DofManager::CompMask speciesMask( m_numDofPerCell, 2, m_numPrimarySpecies+2 );
+
+ dofManager.addVectorToField( localSolution,
+ viewKeyStruct::elemDofFieldString(),
+ fields::flow::pressure::key(),
+ scalingFactor,
+ pressureMask );
+
+ dofManager.addVectorToField( localSolution,
+ viewKeyStruct::elemDofFieldString(),
+ fields::flow::temperature::key(),
+ scalingFactor,
+ temperatureMask );
+
+ dofManager.addVectorToField( localSolution,
+ viewKeyStruct::elemDofFieldString(),
+ fields::flow::logPrimarySpeciesConcentration::key(),
+ scalingFactor,
+ speciesMask );
+ }
+ else
+ {
+ DofManager::CompMask pressureMask( m_numDofPerCell, 0, 1 );
+ DofManager::CompMask speciesMask( m_numDofPerCell, 1, m_numPrimarySpecies+1 );
+
+ dofManager.addVectorToField( localSolution,
+ viewKeyStruct::elemDofFieldString(),
+ fields::flow::pressure::key(),
+ scalingFactor,
+ pressureMask );
+
+ dofManager.addVectorToField( localSolution,
+ viewKeyStruct::elemDofFieldString(),
+ fields::flow::logPrimarySpeciesConcentration::key(),
+ scalingFactor,
+ speciesMask );
+ }
+
+ this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ std::vector< string > fields{ fields::flow::pressure::key() };
+
+ if( m_isThermal )
+ {
+ fields.emplace_back( fields::flow::temperature::key() );
+ }
+
+ fields.emplace_back( fields::flow::logPrimarySpeciesConcentration::key() );
+
+ FieldIdentifiers fieldsToBeSync;
+ fieldsToBeSync.addElementFields( fields, regionNames );
+
+ CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, mesh, domain.getNeighbors(), true );
+ } );
+}
+
+void SinglePhaseReactiveTransport::saveConvergedState( ElementSubRegionBase & subRegion ) const
+{
+ SinglePhaseBase::saveConvergedState( subRegion );
+
+ arrayView2d< real64 const, compflow::USD_COMP > const logPrimaryConc = subRegion.template getField< fields::flow::logPrimarySpeciesConcentration >();
+ arrayView2d< real64, compflow::USD_COMP > const logPrimarySpeciesConc_n = subRegion.template getField< fields::flow::logPrimarySpeciesConcentration_n >();
+ logPrimarySpeciesConc_n.setValues< parallelDevicePolicy<> >( logPrimaryConc );
+
+ arrayView2d< real64 const, compflow::USD_COMP > const primarySpeciesAggregateMole = subRegion.template getField< fields::flow::primarySpeciesAggregateMole >();
+ arrayView2d< real64, compflow::USD_COMP > const primarySpeciesAggregateMole_n = subRegion.template getField< fields::flow::primarySpeciesAggregateMole_n >();
+ primarySpeciesAggregateMole_n.setValues< parallelDevicePolicy<> >( primarySpeciesAggregateMole );
+}
+
+namespace
+{
+char const faceBcLogMessage[] =
+ "SinglePhaseReactiveTransport {}: at time {}s, "
+ "the <{}> boundary condition '{}' is applied to the face set '{}' in '{}'. "
+ "\nThe scale of this boundary condition is {} and multiplies the value of the provided function (if any). "
+ "\nThe total number of target faces (including ghost faces) is {}."
+ "\nNote that if this number is equal to zero, the boundary condition will not be applied on this face set.";
+}
+
+void SinglePhaseReactiveTransport::applyFaceDirichletBC( real64 const time_n,
+ real64 const dt,
+ DofManager const & dofManager,
+ DomainPartition & domain,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+
+ array1d< integer > mobilePrimarySpeciesFlags;
+ mobilePrimarySpeciesFlags.resize( m_numPrimarySpecies );
+
+ for( integer i=0; i 0 )
+ {
+ for( integer i = 0; i < m_immobilePrimarySpeciesIndices.size(); ++i )
+ {
+ localIndex const immobileSpeciesIndex = m_immobilePrimarySpeciesIndices[i];
+ mobilePrimarySpeciesFlags[immobileSpeciesIndex] = 0;
+ }
+ }
+
+ FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance();
+
+ NumericalMethodsManager const & numericalMethodManager = domain.getNumericalMethodManager();
+ FiniteVolumeManager const & fvManager = numericalMethodManager.getFiniteVolumeManager();
+ FluxApproximationBase const & fluxApprox = fvManager.getFluxApproximation( m_discretizationName );
+
+ string const & dofKey = dofManager.getKey( SinglePhaseBase::viewKeyStruct::elemDofFieldString() );
+
+ this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & )
+ {
+ FaceManager & faceManager = mesh.getFaceManager();
+ ElementRegionManager & elemManager = mesh.getElemManager();
+
+ if( m_isThermal )
+ {
+ // Take BCs defined for "pressure" field and apply values to "facePressure"
+ applyFieldValue< FaceManager >( time_n, dt, mesh, faceBcLogMessage,
+ fields::flow::pressure::key(), fields::flow::facePressure::key() );
+
+ // Take BCs defined for "temperature" field and apply values to "faceTemperature"
+ applyFieldValue< FaceManager >( time_n, dt, mesh, faceBcLogMessage,
+ fields::flow::temperature::key(), fields::flow::faceTemperature::key() );
+
+ // Then launch the face Dirichlet kernel
+ fsManager.apply< FaceManager >( time_n + dt,
+ mesh,
+ fields::flow::pressure::key(), // we have required that pressure is always present
+ [&] ( FieldSpecificationBase const &,
+ string const & setName,
+ SortedArrayView< localIndex const > const &,
+ FaceManager &,
+ string const & )
+ {
+ BoundaryStencil const & stencil = fluxApprox.getStencil< BoundaryStencil >( mesh, setName );
+ if( stencil.size() == 0 )
+ {
+ return;
+ }
+
+ // TODO: same issue as in the single-phase case
+ // currently we just use model from the first cell in this stencil
+ // since it's not clear how to create fluid kernel wrappers for arbitrary models.
+ // Can we just use cell properties for an approximate flux computation?
+ // Then we can forget about capturing the fluid model.
+ localIndex const er = stencil.getElementRegionIndices()( 0, 0 );
+ localIndex const esr = stencil.getElementSubRegionIndices()( 0, 0 );
+ ElementSubRegionBase & subRegion = elemManager.getRegion( er ).getSubRegion( esr );
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid & reactiveFluid = subRegion.getConstitutiveModel< reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid >( fluidName );
+
+ BoundaryStencilWrapper const stencilWrapper = stencil.createKernelWrapper();
+
+ thermalSinglePhaseReactiveFVMKernels::
+ DirichletFluxComputeKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numPrimarySpecies,
+ mobilePrimarySpeciesFlags,
+ dofManager.rankOffset(),
+ dofKey,
+ this->getName(),
+ faceManager,
+ elemManager,
+ stencilWrapper,
+ reactiveFluid,
+ dt,
+ localMatrix,
+ localRhs );
+ } );
+ }
+ else
+ {
+ // Take BCs defined for "pressure" field and apply values to "facePressure"
+ applyFieldValue< FaceManager >( time_n, dt, mesh, faceBcLogMessage,
+ fields::flow::pressure::key(), fields::flow::facePressure::key() );
+
+ // Then launch the face Dirichlet kernel
+ fsManager.apply< FaceManager >( time_n + dt,
+ mesh,
+ fields::flow::pressure::key(), // we have required that pressure is always present
+ [&] ( FieldSpecificationBase const &,
+ string const & setName,
+ SortedArrayView< localIndex const > const &,
+ FaceManager &,
+ string const & )
+ {
+ BoundaryStencil const & stencil = fluxApprox.getStencil< BoundaryStencil >( mesh, setName );
+ if( stencil.size() == 0 )
+ {
+ return;
+ }
+
+ // TODO: same issue as in the single-phase case
+ // currently we just use model from the first cell in this stencil
+ // since it's not clear how to create fluid kernel wrappers for arbitrary models.
+ // Can we just use cell properties for an approximate flux computation?
+ // Then we can forget about capturing the fluid model.
+ localIndex const er = stencil.getElementRegionIndices()( 0, 0 );
+ localIndex const esr = stencil.getElementSubRegionIndices()( 0, 0 );
+ ElementSubRegionBase & subRegion = elemManager.getRegion( er ).getSubRegion( esr );
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ reactivefluid::ReactiveCompressibleSinglePhaseFluid & reactiveFluid = subRegion.getConstitutiveModel< reactivefluid::ReactiveCompressibleSinglePhaseFluid >( fluidName );
+
+ BoundaryStencilWrapper const stencilWrapper = stencil.createKernelWrapper();
+
+ singlePhaseReactiveFVMKernels::
+ DirichletFluxComputeKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numPrimarySpecies,
+ mobilePrimarySpeciesFlags,
+ dofManager.rankOffset(),
+ dofKey,
+ this->getName(),
+ faceManager,
+ elemManager,
+ stencilWrapper,
+ reactiveFluid,
+ dt,
+ localMatrix,
+ localRhs );
+ } );
+ }
+ } );
+}
+
+void SinglePhaseReactiveTransport::assembleEDFMFluxTerms( real64 const GEOS_UNUSED_PARAM( time_n ),
+ real64 const GEOS_UNUSED_PARAM( dt ),
+ DomainPartition const & GEOS_UNUSED_PARAM( domain ),
+ DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ),
+ arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ),
+ string const & GEOS_UNUSED_PARAM( jumpDofKey ) )
+{}
+
+void SinglePhaseReactiveTransport::applyAquiferBC( real64 const GEOS_UNUSED_PARAM( time ),
+ real64 const GEOS_UNUSED_PARAM( dt ),
+ DomainPartition & GEOS_UNUSED_PARAM( domain ),
+ DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ),
+ arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) const
+{}
+
+void SinglePhaseReactiveTransport::assembleStabilizedFluxTerms( real64 const GEOS_UNUSED_PARAM( dt ),
+ DomainPartition const & GEOS_UNUSED_PARAM( domain ),
+ DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ),
+ arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) )
+{}
+
+REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseReactiveTransport, string const &, Group * const )
+
+} /* namespace geos */
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseReactiveTransport.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseReactiveTransport.hpp
new file mode 100644
index 00000000000..92fad383f29
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseReactiveTransport.hpp
@@ -0,0 +1,371 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 SinglePhaseReactiveTransport.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVETRANSPORT_HPP_
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVETRANSPORT_HPP_
+
+#include "fieldSpecification/FieldSpecificationManager.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseFVM.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseReactiveTransportFields.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/AccumulationKernels.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/DirichletFluxComputeKernel.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/FluidUpdateKernel.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/FluxComputeKernel.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ResidualNormKernel.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ReactionUpdateKernel.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalAccumulationKernels.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalDirichletFluxComputeKernel.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalFluxComputeKernel.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.hpp"
+
+
+namespace geos
+{
+
+/**
+ * @class SinglePhaseReactiveTransport
+ *
+ * A solver for single phase reactive transport
+ */
+class SinglePhaseReactiveTransport : public SinglePhaseBase
+{
+
+public:
+
+ /**
+ * @brief main constructor for Group Objects
+ * @param name the name of this instantiation of Group in the repository
+ * @param parent the parent group of this instantiation of Group
+ */
+ SinglePhaseReactiveTransport( const string & name,
+ dataRepository::Group * const parent );
+
+ SinglePhaseReactiveTransport() = delete;
+
+ /// deleted copy constructor
+ SinglePhaseReactiveTransport( SinglePhaseReactiveTransport const & ) = delete;
+
+ /// default move constructor
+ SinglePhaseReactiveTransport( SinglePhaseReactiveTransport && ) = default;
+
+ /// deleted assignment operator
+ SinglePhaseReactiveTransport & operator=( SinglePhaseReactiveTransport const & ) = delete;
+
+ /// deleted move operator
+ SinglePhaseReactiveTransport & operator=( SinglePhaseReactiveTransport && ) = delete;
+
+ /**
+ * @brief default destructor
+ */
+ virtual ~SinglePhaseReactiveTransport() override = default;
+
+ /**
+ * @brief name of the node manager in the object catalog
+ * @return string that contains the catalog name to generate a new NodeManager object through the object catalog.
+ */
+ static string catalogName()
+ {
+ return "SinglePhaseReactiveTransport";
+ }
+
+ /**
+ * @copydoc PhysicsSolverBase::getCatalogName()
+ */
+ string getCatalogName() const override { return catalogName(); }
+
+ virtual void registerDataOnMesh( dataRepository::Group & meshBodies ) override;
+
+ virtual void
+ setupDofs( DomainPartition const & domain,
+ DofManager & dofManager ) const override;
+
+ virtual void
+ implicitStepSetup( real64 const & time_n,
+ real64 const & dt,
+ DomainPartition & domain ) override final;
+
+ virtual void
+ assembleSystem( real64 const time_n,
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
+ virtual void
+ applyBoundaryConditions( real64 const time_n,
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
+ virtual real64
+ calculateResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ DomainPartition const & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs ) override;
+
+ virtual void
+ applySystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain ) override;
+
+ virtual void
+ resetStateToBeginningOfStep( DomainPartition & domain ) override;
+
+ virtual void
+ implicitStepComplete( real64 const & time,
+ real64 const & dt,
+ DomainPartition & domain ) override final;
+
+ virtual void saveConvergedState( ElementSubRegionBase & subRegion ) const override final;
+
+ virtual void
+ updateState ( DomainPartition & domain ) override final;
+
+ void updateMixedReactionSystem( ElementSubRegionBase & subRegion ) const;
+
+ void updateSurfaceArea( ElementSubRegionBase & subRegion ) const;
+
+ void updateSpeciesAmount( ElementSubRegionBase & subRegion ) const;
+
+ void updateKineticReactionMolarIncrements( real64 const dt,
+ ElementSubRegionBase & subRegion ) const;
+
+ virtual void updateFluidModel( ObjectManagerBase & dataGroup ) const override;
+
+ virtual void updatePorosityAndPermeability( CellElementSubRegion & subRegion ) const override;
+
+ virtual void initializePostInitialConditionsPreSubGroups() override;
+
+ virtual void initializeFluidState( MeshLevel & mesh, string_array const & regionNames ) override;
+
+ void initializeEquilibriumReaction( ElementSubRegionBase & subRegion ) const;
+
+ /**
+ * @brief Checks constitutive models for consistency
+ * @param[in] domain the domain partition
+ */
+ virtual void validateConstitutiveModels( DomainPartition & domain ) const override final;
+
+ /**
+ * @brief Getter for the number of fluid components (species)
+ * @return the number of components
+ */
+ integer numPrimarySpecies() const { return m_numPrimarySpecies; }
+
+ /**
+ * @brief assembles the accumulation terms in total mass balance and primary species amount equation for all cells
+ * @param dt time step
+ * @param domain the physical domain object
+ * @param dofManager degree-of-freedom manager associated with the linear system
+ * @param localMatrix the system matrix
+ * @param localRhs the system right-hand side vector
+ */
+ void assembleAccumulationTermsInMassBalanceAndSpeciesAmountEqs( real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) const;
+
+ /**
+ * @brief assembles the flux terms for all cells
+ * @param dt time step
+ * @param domain the physical domain object
+ * @param dofManager degree-of-freedom manager associated with the linear system
+ * @param matrix the system matrix
+ * @param rhs the system right-hand side vector
+ */
+ virtual void
+ assembleFluxTerms( real64 const dt,
+ DomainPartition const & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
+ /**
+ * @brief Apply source flux boundary conditions to the system
+ * @param time current time
+ * @param dt time step
+ * @param dofManager degree-of-freedom manager associated with the linear system
+ * @param domain the domain
+ * @param localMatrix local system matrix
+ * @param localRhs local system right-hand side vector
+ */
+ virtual void
+ applySourceFluxBC( real64 const time_n,
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) const override;
+
+ /**
+ * @brief Function to perform the Application of Dirichlet type BC's
+ * @param time current time
+ * @param dt time step
+ * @param dofManager degree-of-freedom manager associated with the linear system
+ * @param domain the domain
+ * @param localMatrix local system matrix
+ * @param localRhs local system right-hand side vector
+ */
+ virtual void
+ applyDirichletBC( real64 const time_n,
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) const override;
+
+ /**
+ * @brief Utility function that encapsulates the call to FieldSpecificationBase::applyFieldValue in BC application
+ * @param[in] time_n the time at the beginning of the step
+ * @param[in] dt the time step
+ * @param[in] mesh the mesh level object
+ * @param[in] logMessage the log message issued by the solver if the bc is called
+ * @param[in] fieldKey the key of the field specified in the xml file
+ * @param[in] boundaryFieldKey the key of the boundary field
+ */
+ template< typename OBJECT_TYPE >
+ void applyFieldValue( real64 const & time_n,
+ real64 const & dt,
+ MeshLevel & mesh,
+ char const logMessage[],
+ string const fieldKey,
+ string const boundaryFieldKey ) const;
+
+ virtual void
+ applyAquiferBC( real64 const time,
+ real64 const dt,
+ DomainPartition & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) const override;
+
+ virtual void
+ assembleEDFMFluxTerms( real64 const time_n,
+ real64 const dt,
+ DomainPartition const & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs,
+ string const & jumpDofKey ) override final;
+
+ virtual void
+ assembleStabilizedFluxTerms( real64 const dt,
+ DomainPartition const & domain,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
+ struct viewKeyStruct : SinglePhaseBase::viewKeyStruct
+ {
+ static constexpr char const * diffusionNamesString() { return "diffusionNames"; }
+ static constexpr char const * isUpdateReactivePorosityString() { return "isUpdateReactivePorosity"; }
+ static constexpr char const * isUpdateSurfaceAreaString() { return "isUpdateSurfaceArea"; }
+ static constexpr char const * immobilePrimarySpeciesIndicesString() { return "immobilePrimarySpeciesIndices"; }
+ };
+
+protected:
+
+ /// the number of primary species in the fluid
+ integer m_numPrimarySpecies;
+
+ /// the number of kinetic reactions
+ integer m_numKineticReactions;
+
+ /// name of the reactive fluid constitutive model
+ string m_reactiveFluidModelName;
+
+ /// flag to determine whether or not to apply diffusion
+ integer m_hasDiffusion;
+
+ /// flag to determine whether or not to use the reactive porosity
+ integer m_isUpdateReactivePorosity;
+
+ /// flag to determine whether or not to update the surface area
+ integer m_isUpdateSurfaceArea;
+
+ /// array to store the indices of immobile primary species
+ array1d< integer > m_immobilePrimarySpeciesIndices;
+
+private:
+
+ /**
+ * @brief Function to perform the application of Dirichlet BCs on faces
+ * @param time_n current time
+ * @param dt time step
+ * @param faceSet degree-of-freedom manager associated with the linear system
+ * @param domain the domain
+ * @param matrix the system matrix
+ * @param rhs the system right-hand side vector
+ */
+ void applyFaceDirichletBC( real64 const time_n,
+ real64 const dt,
+ DofManager const & faceSet,
+ DomainPartition & domain,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs );
+
+};
+
+template< typename OBJECT_TYPE >
+void SinglePhaseReactiveTransport::applyFieldValue( real64 const & time_n,
+ real64 const & dt,
+ MeshLevel & mesh,
+ char const logMessage[],
+ string const fieldKey,
+ string const boundaryFieldKey ) const
+{
+ FieldSpecificationManager & fsManager = FieldSpecificationManager::getInstance();
+
+ fsManager.apply< OBJECT_TYPE >( time_n + dt,
+ mesh,
+ fieldKey,
+ [&]( FieldSpecificationBase const & fs,
+ string const & setName,
+ SortedArrayView< localIndex const > const & lset,
+ OBJECT_TYPE & targetGroup,
+ string const & )
+ {
+ if( fs.getLogLevel() >= 1 && m_nonlinearSolverParameters.m_numNewtonIterations == 0 )
+ {
+ globalIndex const numTargetElems = MpiWrapper::sum< globalIndex >( lset.size() );
+ GEOS_LOG_RANK_0( GEOS_FMT( logMessage,
+ getName(), time_n+dt, fs.getCatalogName(), fs.getName(),
+ setName, targetGroup.getName(), fs.getScale(), numTargetElems ) );
+ }
+
+ // Specify the bc value of the field
+ fs.applyFieldValue< FieldSpecificationEqual,
+ parallelDevicePolicy<> >( lset,
+ time_n + dt,
+ targetGroup,
+ boundaryFieldKey );
+ } );
+}
+
+} /* namespace geos */
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVETRANSPORT_HPP_
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseReactiveTransportFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseReactiveTransportFields.hpp
new file mode 100644
index 00000000000..28c72f5c170
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseReactiveTransportFields.hpp
@@ -0,0 +1,116 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
+ * Copyright (c) 2023-2024 Chevron
+ * Copyright (c) 2019- GEOS/GEOSX Contributors
+ * All rights reserved
+ *
+ * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
+ * ------------------------------------------------------------------------------------------------------------
+ */
+
+/**
+ * @file SinglePhaseReactiveTransportFields.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVETRANSPORTFIELDS_HPP_
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVETRANSPORTFIELDS_HPP_
+
+#include "mesh/MeshFields.hpp"
+
+namespace geos
+{
+/**
+ * A scope for field traits.
+ */
+namespace fields
+{
+
+namespace flow
+{
+using array2dLayoutComp = array2d< real64, compflow::LAYOUT_COMP >;
+using array2dLayoutFluid_dC = array2d< real64, compflow::LAYOUT_FLUID_DC >;
+
+DECLARE_FIELD( logPrimarySpeciesConcentration,
+ "logPrimarySpeciesConcentration",
+ array2dLayoutComp,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Natural log of primary species concentration (molarity)" );
+
+DECLARE_FIELD( logPrimarySpeciesConcentration_n,
+ "logPrimarySpeciesConcentration_n",
+ array2dLayoutComp,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Natural log of primary species concentration (molarity) at the previous converged time step" );
+
+DECLARE_FIELD( bcLogPrimarySpeciesConcentration,
+ "bcLogPrimarySpeciesConcentration",
+ array2dLayoutComp,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Boundary condition for natural log of primary species concentration (molarity)" );
+
+DECLARE_FIELD( primarySpeciesAggregateMole,
+ "primarySpeciesAggregateMole",
+ array2dLayoutComp,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Aggregate amount of primary species in mole" );
+
+DECLARE_FIELD( primarySpeciesAggregateMole_n,
+ "primarySpeciesAggregateMole_n",
+ array2dLayoutComp,
+ 0,
+ LEVEL_0,
+ WRITE_AND_READ,
+ "Aggregate amount of primary species in mole at the previous converged time step" );
+
+DECLARE_FIELD( kineticReactionMolarIncrements,
+ "kineticReactionMolarIncrements",
+ array2dLayoutComp,
+ 0,
+ NOPLOT,
+ WRITE_AND_READ,
+ "Molar increment in the current timestep for kinetic reactions" );
+
+DECLARE_FIELD( dMobility_dLogPrimaryConc,
+ "dMobility_dLogPrimaryConc",
+ array2dLayoutFluid_dC,
+ 0,
+ NOPLOT,
+ NO_WRITE,
+ "Derivative of fluid mobility with respect to log of primary species concentration" );
+
+DECLARE_FIELD( surfaceArea,
+ "surfaceArea",
+ array2dLayoutComp,
+ 0,
+ NOPLOT,
+ WRITE_AND_READ,
+ "Surface area for surface reactions." );
+
+DECLARE_FIELD( initialSurfaceArea,
+ "initialSurfaceArea",
+ array2dLayoutComp,
+ 0,
+ NOPLOT,
+ WRITE_AND_READ,
+ "Initial surface area for surface reactions." );
+
+}
+
+}
+
+}
+
+#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVETRANSPORTFIELDS_HPP_
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp
index b321eab6a44..13393664683 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp
@@ -57,8 +57,8 @@ class AccumulationKernel
/// Note: Derivative lineup only supports dP & dT, not component terms
- static constexpr integer isThermal = NUM_DOF-1;
- using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< isThermal >;
+ // static constexpr integer isThermal = NUM_DOF-1;
+ using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< 0 >; // Why not just input 0
/**
* @brief Constructor
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp
index 15c9ecc7a48..000c4d0b254 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp
@@ -27,6 +27,7 @@
#include "finiteVolume/BoundaryStencil.hpp"
#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp"
#include "physicsSolvers/fluidFlow/StencilAccessors.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp"
#include "physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp"
#include "codingUtilities/Utilities.hpp"
@@ -44,8 +45,8 @@ namespace singlePhaseFVMKernels
* @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms
*/
template< integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER >
-class DirichletFluxComputeKernel : public FluxComputeKernel< NUM_EQN, NUM_DOF,
- BoundaryStencilWrapper >
+class DirichletFluxComputeKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF,
+ BoundaryStencilWrapper >
{
public:
using Deriv = constitutive::singlefluid::DerivativeOffset;
@@ -223,10 +224,14 @@ class DirichletFluxComputeKernel : public FluxComputeKernel< NUM_EQN, NUM_DOF,
real64 const mobility_up = mobility[k_up];
real64 const dMobility_dP_up = dMobility_dP[k_up];
+ // Upwind density
+ real64 const dens_up = ( potDif >= 0 ) ? m_dens[er][esr][ei][0] : faceDens;
+ real64 const dDens_dP_up = ( potDif >= 0 ) ? m_dDens[er][esr][ei][0][Deriv::dP] : 0.0;
+
// call the lambda in the phase loop to allow the reuse of the fluxes and their derivatives
// possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase
- compFluxKernelOp( er, esr, ei, kf, f, dF_dP, mobility_up, dMobility_dP_up );
+ compFluxKernelOp( er, esr, ei, kf, f, dF_dP, mobility_up, dMobility_dP_up, dens_up, dDens_dP_up );
// *** end of upwinding
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp
index e2e92b14792..c470b9790a1 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp
@@ -51,8 +51,8 @@ class AccumulationKernel : public singlePhaseBaseKernels::AccumulationKernel< SU
using Base::m_dMass;
/// Note: Derivative lineup only supports dP & dT, not component terms
- static constexpr integer isThermal = NUM_DOF-1;
- using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< isThermal >;
+ // static constexpr integer isThermal = NUM_DOF-1;
+ using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< 1 >;
/**
* @brief Constructor
* @param[in] rankOffset the offset of my MPI rank
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp
index bcd1b1bc880..b8e863d9ac0 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp
@@ -200,8 +200,11 @@ class DirichletFluxComputeKernel : public singlePhaseFVMKernels::DirichletFluxCo
real64 const & f,
real64 const & dF_dP,
real64 const & mobility_up,
- real64 const & dMobility_dP_up )
+ real64 const & dMobility_dP_up,
+ real64 const & dens_up,
+ real64 const & dDens_dP_up )
{
+ GEOS_UNUSED_VAR( dens_up, dDens_dP_up );
// Compute the derivatives of the density wrt temperature
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/AccumulationKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/AccumulationKernels.hpp
new file mode 100644
index 00000000000..28c3b1cc181
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/AccumulationKernels.hpp
@@ -0,0 +1,330 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 AccumulationKernels.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_ACCUMULATIONKERNELS_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_ACCUMULATIONKERNELS_HPP
+
+#include "common/DataLayouts.hpp"
+#include "common/DataTypes.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp"
+#include "constitutive/solid/CoupledSolidBase.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/KernelLaunchSelectors.hpp"
+
+namespace geos
+{
+
+namespace singlePhaseReactiveBaseKernels
+{
+
+/******************************** AccumulationKernel ********************************/
+
+/**
+ * @class AccumulationKernel
+ * @brief Define the interface for the assembly kernel in charge of accumulation
+ */
+template< typename SUBREGION_TYPE, integer NUM_DOF, integer NUM_SPECIES, typename BASE_FLUID_TYPE >
+class AccumulationKernel : public singlePhaseBaseKernels::AccumulationKernel< SUBREGION_TYPE, NUM_DOF >
+{
+
+public:
+
+ using Base = singlePhaseBaseKernels::AccumulationKernel< SUBREGION_TYPE, NUM_DOF >;
+ using Base::numDof;
+ using Base::numEqn;
+ using Base::m_rankOffset;
+ using Base::m_dofNumber;
+ using Base::m_elemGhostRank;
+ using Base::m_localMatrix;
+ using Base::m_localRhs;
+ using Base::m_dMass;
+
+ /// Note: Derivative lineup only supports dP & dT, not component terms
+ using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< 0 >;
+
+ /// Compile time value for the number of primary species
+ static constexpr integer numSpecies = NUM_SPECIES;
+
+ /**
+ * @brief Constructor
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] dofKey the string key to retrieve the degress of freedom numbers
+ * @param[in] subRegion the element subregion
+ * @param[in] fluid the fluid model
+ * @param[in] solid the solid model
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
+ AccumulationKernel( globalIndex const rankOffset,
+ string const dofKey,
+ SUBREGION_TYPE const & subRegion,
+ constitutive::reactivefluid::ReactiveSinglePhaseFluid< BASE_FLUID_TYPE > const & fluid,
+ constitutive::CoupledSolidBase const & solid,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ : Base( rankOffset, dofKey, subRegion, localMatrix, localRhs ),
+ m_dt( dt ),
+ m_volume( subRegion.getElementVolume() ),
+ m_deltaVolume( subRegion.template getField< fields::flow::deltaVolume >() ),
+ m_porosity( solid.getPorosity() ),
+ m_dPoro_dPres( solid.getDporosity_dPressure() ),
+ // m_dDensity_dLogPrimaryConc( fluid.dDensity_dLogPrimaryConc() ),
+ // m_dPoro_dLogPrimaryConc( solid.getDporosity_dLogPrimaryConc() ),
+ m_primarySpeciesAggregateConcentration( fluid.primarySpeciesAggregateConcentration() ),
+ // m_dPrimarySpeciesAggregateConcentration_dPres( fluid.dPrimarySpeciesAggregateConcentration_dPres() ),
+ m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations( fluid.dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations() ),
+ m_primarySpeciesAggregateKineticRate( fluid.aggregateSpeciesRates() ),
+ // m_dPrimarySpeciesAggregateKineticRate_dPres( fluid.dPrimarySpeciesAggregateKineticRate_dPres() ),
+ m_dPrimarySpeciesAggregateKineticRate_dLogPrimaryConc( fluid.dAggregateSpeciesRates_dLogPrimarySpeciesConcentrations() ),
+ m_primarySpeciesAggregateMole_n( subRegion.template getField< fields::flow::primarySpeciesAggregateMole_n >() )
+ {}
+
+ /**
+ * @struct StackVariables
+ * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack
+ */
+ struct StackVariables : public Base::StackVariables
+ {
+public:
+
+ GEOS_HOST_DEVICE
+ StackVariables()
+ : Base::StackVariables()
+ {}
+
+ using Base::StackVariables::localRow;
+ using Base::StackVariables::dofIndices;
+ using Base::StackVariables::localResidual;
+ using Base::StackVariables::localJacobian;
+
+ // Pore volume information
+
+ /// Pore volume at time n+1
+ real64 poreVolume = 0.0;
+
+ /// Derivative of pore volume with respect to pressure
+ real64 dPoreVolume_dPres = 0.0;
+
+ /// Derivative of pore volume with respect to each primary species concentration
+ real64 dPoreVolume_dLogPrimaryConc[numSpecies]{};
+
+ };
+
+ /**
+ * @brief Performs the setup phase for the kernel.
+ * @param[in] ei the element index
+ * @param[in] stack the stack variables
+ */
+ GEOS_HOST_DEVICE
+ void setup( localIndex const ei,
+ StackVariables & stack ) const
+ {
+ // initialize the pore volume
+ stack.poreVolume = ( m_volume[ei] + m_deltaVolume[ei] ) * m_porosity[ei][0];
+ stack.dPoreVolume_dPres = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dPres[ei][0];
+
+ Base::setup( ei, stack );
+
+ // // is - index of the primary species
+ // for( integer is = 0; is < numSpecies; ++is )
+ // {
+ // stack.dPoreVolume_dLogPrimaryConc[is] = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dLogPrimaryConc[ei][is]
+ // }
+ }
+
+ /**
+ * @brief Compute the local accumulation contributions to the residual and Jacobian
+ * @param[in] ei the element index
+ * @param[inout] stack the stack variables
+ * @param[in] kernelOp the function used to customize the kernel
+ */
+ GEOS_HOST_DEVICE
+ void computeAccumulation( localIndex const ei,
+ StackVariables & stack ) const
+ {
+ // Residual[is] += (primarySpeciesAggregateConcentration[is] * stack.poreVolume - primarySpeciesAggregateMole_n[is])
+ // - dt * m_volume * primarySpeciesKineticRate[is] // To Check: what's the unit of the kinetic rate
+
+ Base::computeAccumulation( ei, stack );
+
+ // Step 1: assemble the derivatives of the total mass equation w.r.t log of primary species concentration
+ // for( integer is = 0; is < numSpecies; ++is )
+ // {
+ // stack.localJacobian[0][is+numDof-numSpecies] = stack.poreVolume * m_dDensity_dLogPrimaryConc[ei][is] +
+ // stack.dPoreVolume_dLogPrimaryConc[is] * m_density[ei][0];
+ // }
+
+ arraySlice2d< real64 const,
+ constitutive::reactivefluid::USD_SPECIES_DC -
+ 2 > dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations = m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations[ei][0];
+ arraySlice2d< real64 const, constitutive::reactivefluid::USD_SPECIES_DC - 2 > dPrimarySpeciesAggregateKineticRate_dLogPrimaryConc = m_dPrimarySpeciesAggregateKineticRate_dLogPrimaryConc[ei][0];
+
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ // Step 2: assemble the accumulation term of the species mass balance equation
+ // Step 2.1: residual
+ // Primary species mole amount in pore volume
+ stack.localResidual[is+numEqn-numSpecies] -= m_primarySpeciesAggregateMole_n[ei][is];
+ stack.localResidual[is+numEqn-numSpecies] += m_primarySpeciesAggregateConcentration[ei][0][is] * stack.poreVolume;
+
+ // Reaction term
+ stack.localResidual[is+numEqn-numSpecies] -= m_dt * ( m_volume[ei] + m_deltaVolume[ei] ) * m_primarySpeciesAggregateKineticRate[ei][0][is];
+
+ // Step 2.1: jacobian
+ // Drivative of primary species amount in pore volume wrt pressure
+ stack.localJacobian[is+numEqn-numSpecies][0] += stack.dPoreVolume_dPres * m_primarySpeciesAggregateConcentration[ei][0][is]
+ /* + stack.poreVolume * m_dTotalPrimarySpeciesConcentration_dPres[ei][is] */;
+ // // Derivative of reaction term wrt pressure
+ // stack.localJacobian[is+numEqn-numSpecies][0] -= m_dt * ( m_volume[ei] + m_deltaVolume[ei] ) *
+ // m_dPrimarySpeciesTotalKineticRate_dPres[is];
+
+ // Derivative wrt log of primary species concentration
+ for( integer js = 0; js < numSpecies; ++js )
+ {
+ stack.localJacobian[is+numEqn-numSpecies][js+numDof-numSpecies] = /* stack.dPoreVolume_dLogPrimaryConc[js] *
+ m_primarySpeciesAggregateConcentration[ei][0][is]
+ + */stack.poreVolume * dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations[is][js]; // To
+ // check
+ // if
+ // the
+ // permutation
+ // is
+ // consistent
+
+ stack.localJacobian[is+numEqn-numSpecies][js+numDof-numSpecies] -= m_dt * ( m_volume[ei] + m_deltaVolume[ei] ) * dPrimarySpeciesAggregateKineticRate_dLogPrimaryConc[is][js];
+ }
+ }
+ }
+
+ /**
+ * @brief Performs the complete phase for the kernel.
+ * @param[in] ei the element index
+ * @param[inout] stack the stack variables
+ */
+ GEOS_HOST_DEVICE
+ void complete( localIndex const ei,
+ StackVariables & stack ) const
+ {
+ // Step 1: assemble the total mass balance equation
+ // - the total mass balance equations (i = 0)
+ Base::complete( ei, stack );
+
+ // Step 2: assemble the primary species mole amount balance equation
+ // - the species mole amount balance equations (i = numEqn-numSpecies to i = numEqn-1)
+ integer const beginRowSpecies = numEqn-numSpecies;
+ for( integer i = 0; i < numSpecies; ++i )
+ {
+ m_localRhs[stack.localRow + beginRowSpecies + i] += stack.localResidual[beginRowSpecies+i];
+ m_localMatrix.template addToRow< serialAtomic >( stack.localRow + beginRowSpecies + i,
+ stack.dofIndices,
+ stack.localJacobian[beginRowSpecies + i],
+ numDof );
+ }
+ }
+
+protected:
+
+ /// Time step size
+ real64 const m_dt;
+
+ /// View on the element volumes
+ arrayView1d< real64 const > const m_volume;
+ arrayView1d< real64 const > const m_deltaVolume;
+
+ /// Views on the porosity
+ arrayView2d< real64 const > const m_porosity;
+ arrayView2d< real64 const > const m_dPoro_dPres;
+
+ // // View on the derivatives of fluid density wrt log of primary species concentration
+ // arrayView2d< real64 const, compflow::USD_COMP > m_dDensity_dLogPrimaryConc;
+
+ // // View on the derivatives of porosity wrt log of primary species concentration
+ // arrayView2d< real64 const, compflow::USD_COMP > m_dPoro_dLogPrimaryConc;
+
+ // View on the total concentration of ions that contain the primary species
+ arrayView3d< real64 const, constitutive::reactivefluid::USD_SPECIES > m_primarySpeciesAggregateConcentration;
+
+ // // View on the derivatives of aggregate concentration for the primary species wrt pressure
+ // arrayView2d< real64 const, compflow::USD_COMP > m_dPrimarySpeciesAggregateConcentration_dPres;
+
+ // View on the derivatives of total ion concentration for the primary species wrt log of primary species concentration
+ arrayView4d< real64 const, constitutive::reactivefluid::USD_SPECIES_DC > m_dPrimarySpeciesAggregateConcentration_dLogPrimarySpeciesConcentrations;
+
+ // View on the aggregate kinetic rate of primary species from all reactions
+ arrayView3d< real64 const, constitutive::reactivefluid::USD_SPECIES > m_primarySpeciesAggregateKineticRate;
+
+ // // View on the derivatives of aggregate kinetic rate of primary species wrt pressure
+ // arrayView2d< real64 const, compflow::USD_COMP > m_dPrimarySpeciesAggregateKineticRate_dPres;
+
+ // View on the derivatives of aggregate kinetic rate of primary species wrt log of primary species concentration
+ arrayView4d< real64 const, constitutive::reactivefluid::USD_SPECIES_DC > m_dPrimarySpeciesAggregateKineticRate_dLogPrimaryConc;
+
+ // View on primary species mole amount from previous time step
+ arrayView2d< real64 const, compflow::USD_COMP > m_primarySpeciesAggregateMole_n;
+};
+
+/**
+ * @class AccumulationKernelFactory
+ */
+class AccumulationKernelFactory
+{
+public:
+
+ /**
+ * @brief Create a new kernel and launch
+ * @tparam POLICY the policy used in the RAJA kernel
+ * @param[in] numSpecies the number of primary species
+ * @param[in] dt time step
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] dofKey the string key to retrieve the degress of freedom numbers
+ * @param[in] subRegion the element subregion
+ * @param[in] fluid the fluid model
+ * @param[in] solid the solid model
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
+ template< typename POLICY, typename SUBREGION_TYPE, typename BASE_FLUID_TYPE >
+ static void
+ createAndLaunch( integer const numSpecies,
+ real64 const dt,
+ globalIndex const rankOffset,
+ string const dofKey,
+ SUBREGION_TYPE const & subRegion,
+ constitutive::reactivefluid::ReactiveSinglePhaseFluid< BASE_FLUID_TYPE > const & fluid,
+ constitutive::CoupledSolidBase const & solid,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ internal::kernelLaunchSelectorCompSwitch( numSpecies, [&] ( auto NS )
+ {
+ integer constexpr NUM_SPECIES = NS();
+ integer constexpr NUM_DOF = 1+NS();
+ AccumulationKernel< SUBREGION_TYPE, NUM_DOF, NUM_SPECIES, BASE_FLUID_TYPE > kernel( rankOffset, dofKey, subRegion, fluid, solid, dt, localMatrix, localRhs );
+ AccumulationKernel< SUBREGION_TYPE, NUM_DOF, NUM_SPECIES, BASE_FLUID_TYPE >::template launch< POLICY >( subRegion.size(), kernel );
+ } );
+ }
+};
+
+} // namespace singlePhaseReactiveBaseKernels
+
+} // namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_ACCUMULATIONKERNELS_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/DirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/DirichletFluxComputeKernel.hpp
new file mode 100644
index 00000000000..80ff9bce9ba
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/DirichletFluxComputeKernel.hpp
@@ -0,0 +1,362 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 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 DirichletFluxComputeKernel.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_DIRICHLETFLUXCOMPUTEKERNEL_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_DIRICHLETFLUXCOMPUTEKERNEL_HPP
+
+#include "constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveFluidFields.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveFluidSelector.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp"
+
+namespace geos
+{
+
+namespace singlePhaseReactiveFVMKernels
+{
+
+/******************************** DirichletFluxComputeKernel ********************************/
+
+/**
+ * @class DirichletFluxComputeKernel
+ * @tparam NUM_SPECIES number of fluid primary species
+ * @tparam NUM_EQN number of equations
+ * @tparam NUM_DOF number of degrees of freedom
+ * @tparam FLUIDWRAPPER the type of the fluid wrapper
+ * @tparam BASE_FLUID_TYPE the type of the base model for the reactive fluid model
+ * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms
+ */
+template< integer NUM_SPECIES, integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER, typename BASE_FLUID_TYPE >
+class DirichletFluxComputeKernel : public singlePhaseFVMKernels::DirichletFluxComputeKernel< NUM_EQN, NUM_DOF,
+ FLUIDWRAPPER >
+{
+public:
+ /// Compile time value for the number of primary species
+ static constexpr integer numSpecies = NUM_SPECIES;
+
+ /**
+ * @brief The type for element-based data. Consists entirely of ArrayView's.
+ *
+ * Can be converted from ElementRegionManager::ElementViewConstAccessor
+ * by calling .toView() or .toViewConst() on an accessor instance
+ */
+ template< typename VIEWTYPE >
+ using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >;
+
+ using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase;
+ using DofNumberAccessor = AbstractBase::DofNumberAccessor;
+ using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors;
+ using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors;
+ using PermeabilityAccessors = AbstractBase::PermeabilityAccessors;
+
+ using AbstractBase::m_dt;
+ using AbstractBase::m_rankOffset;
+ using AbstractBase::m_dofNumber;
+ using AbstractBase::m_dens;
+ using AbstractBase::m_dDens;
+
+ using Base = singlePhaseFVMKernels::DirichletFluxComputeKernel< NUM_EQN, NUM_DOF,
+ FLUIDWRAPPER >;
+ using Base::numDof;
+ using Base::numEqn;
+ using Base::m_stencilWrapper;
+ using Base::m_seri;
+ using Base::m_sesri;
+ using Base::m_sei;
+
+ using Base::m_facePres;
+ using Base::m_fluidWrapper;
+
+ using ReactiveSinglePhaseFlowAccessors =
+ StencilAccessors< fields::flow::logPrimarySpeciesConcentration,
+ fields::flow::dMobility_dLogPrimaryConc >;
+
+ using ReactiveSinglePhaseFluidAccessors =
+ StencilMaterialAccessors< constitutive::reactivefluid::ReactiveSinglePhaseFluid< BASE_FLUID_TYPE >,
+ fields::reactivefluid::primarySpeciesMobileAggregateConcentration,
+ fields::reactivefluid::dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations >;
+
+ /**
+ * @brief Constructor for the kernel interface
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] faceManager the face manager
+ * @param[in] stencilWrapper reference to the stencil wrapper
+ * @param[in] fluidWrapper reference to the fluid wrapper
+ * @param[in] dofNumberAccessor
+ * @param[in] singlePhaseFlowAccessors
+ * @param[in] singlePhaseFluidAccessors
+ * @param[in] permeabilityAccessors
+ * @param[in] dt time step size
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
+ DirichletFluxComputeKernel( globalIndex const rankOffset,
+ FaceManager const & faceManager,
+ BoundaryStencilWrapper const & stencilWrapper,
+ FLUIDWRAPPER const & fluidWrapper,
+ DofNumberAccessor const & dofNumberAccessor,
+ SinglePhaseFlowAccessors const & singlePhaseFlowAccessors,
+ ReactiveSinglePhaseFlowAccessors const & reactiveSinglePhaseFlowAccessors,
+ SinglePhaseFluidAccessors const & singlePhaseFluidAccessors,
+ ReactiveSinglePhaseFluidAccessors const & reactiveSinglePhaseFluidAccessors,
+ PermeabilityAccessors const & permeabilityAccessors,
+ arrayView1d< integer const > const & mobilePrimarySpeciesFlags,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ : Base( rankOffset,
+ faceManager,
+ stencilWrapper,
+ fluidWrapper,
+ dofNumberAccessor,
+ singlePhaseFlowAccessors,
+ singlePhaseFluidAccessors,
+ permeabilityAccessors,
+ dt,
+ localMatrix,
+ localRhs ),
+ m_dMob_dLogPrimaryConc( reactiveSinglePhaseFlowAccessors.get( fields::flow::dMobility_dLogPrimaryConc {} ) ),
+ m_primarySpeciesMobileAggregateConc( reactiveSinglePhaseFluidAccessors.get( fields::reactivefluid::primarySpeciesMobileAggregateConcentration {} ) ),
+ m_dPrimarySpeciesMobileAggregateConc_dLogPrimaryConc( reactiveSinglePhaseFluidAccessors.get(
+ fields::reactivefluid::dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations {} ) ),
+ m_mobilePrimarySpeciesFlags( mobilePrimarySpeciesFlags )
+ {}
+
+ /**
+ * @struct StackVariables
+ * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack
+ */
+ struct StackVariables : public Base::StackVariables
+ {
+public:
+
+ /**
+ * @brief Constructor for the stack variables
+ * @param[in] size size of the stencil for this connection
+ * @param[in] numElems number of elements for this connection
+ */
+ GEOS_HOST_DEVICE
+ StackVariables( localIndex const size, localIndex numElems )
+ : Base::StackVariables( size, numElems )
+ {}
+
+ using Base::StackVariables::transmissibility;
+ using Base::StackVariables::dofColIndices;
+ using Base::StackVariables::localFlux;
+ using Base::StackVariables::localFluxJacobian;
+
+ };
+
+ /**
+ * @brief Compute the local Dirichlet face flux contributions to the residual and Jacobian
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes
+ */
+ template< typename FUNC = NoOpFunc >
+ GEOS_HOST_DEVICE
+ void computeFlux( localIndex const iconn,
+ StackVariables & stack,
+ FUNC && compFluxKernelOp = NoOpFunc{} ) const
+ {
+ Base::computeFlux( iconn, stack, [&] ( localIndex const seri,
+ localIndex const sesri,
+ localIndex const sei,
+ localIndex const kf,
+ real64 const & fluxVal,
+ real64 const & dFlux_dP,
+ real64 const & mobility_up,
+ real64 const & dMobility_dP_up,
+ real64 const & dens_up,
+ real64 const & dDens_dP_up )
+ {
+ GEOS_UNUSED_VAR( kf );
+
+ real64 speciesFlux[numSpecies]{};
+ real64 dSpeciesFlux_dP[numSpecies]{};
+ real64 dSpeciesFlux_dLogConc[numSpecies][numSpecies]{};
+
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ real64 const aggregateConc_i = m_primarySpeciesMobileAggregateConc[seri][sesri][sei][0][is];
+ speciesFlux[is] = aggregateConc_i / dens_up * fluxVal * mobility_up;
+
+ dSpeciesFlux_dP[is] = aggregateConc_i / dens_up * dFlux_dP * mobility_up
+ + aggregateConc_i / dens_up * fluxVal * dMobility_dP_up
+ - aggregateConc_i * fluxVal * mobility_up * dDens_dP_up / (dens_up * dens_up);
+
+ for( integer js = 0; js < numSpecies; ++js )
+ {
+ real64 const dAggregateConc_i_dLogConc_j = m_dPrimarySpeciesMobileAggregateConc_dLogPrimaryConc[seri][sesri][sei][0][is][js];
+ dSpeciesFlux_dLogConc[is][js] += dAggregateConc_i_dLogConc_j / dens_up * fluxVal * mobility_up;
+ }
+ }
+
+ /// populate local flux vector and derivatives
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ stack.localFlux[numEqn - numSpecies + is] = m_dt * speciesFlux[is] * m_mobilePrimarySpeciesFlags[is];
+ stack.localFluxJacobian[numEqn - numSpecies + is][0] = m_dt * dSpeciesFlux_dP[is] * m_mobilePrimarySpeciesFlags[is];
+
+ for( integer js = 0; js < numSpecies; ++js )
+ {
+ stack.localFluxJacobian[numEqn - numSpecies + is][numDof - numSpecies + js] += m_dt * dSpeciesFlux_dLogConc[is][js] * m_mobilePrimarySpeciesFlags[is];
+ }
+ }
+
+ compFluxKernelOp( seri, sesri, sei, kf, fluxVal, dFlux_dP, mobility_up, dMobility_dP_up );
+ } );
+ }
+
+ /**
+ * @brief Performs the complete phase for the kernel.
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ */
+ template< typename FUNC = NoOpFunc >
+ GEOS_HOST_DEVICE
+ void complete( localIndex const iconn,
+ StackVariables & stack,
+ FUNC && assemblyKernelOp = NoOpFunc{} ) const
+ {
+ Base::complete( iconn, stack, [&] ( localIndex const localRow )
+ {
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn - numSpecies + is],
+ stack.localFlux[numEqn - numSpecies + is] );
+
+ AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >
+ ( localRow + numEqn - numSpecies + is,
+ stack.dofColIndices,
+ stack.localFluxJacobian[numEqn - numSpecies + is],
+ numDof );
+ }
+
+ assemblyKernelOp( localRow );
+ } );
+ }
+
+protected:
+
+ /// Views on derivatives of fluid mobilities
+ ElementViewConst< arrayView2d< real64 const, compflow::USD_FLUID_DC > > const m_dMob_dLogPrimaryConc;
+
+ /// Views on primary species aggregate concentration
+ ElementViewConst< arrayView3d< real64 const, constitutive::reactivefluid::USD_SPECIES > > const m_primarySpeciesMobileAggregateConc;
+
+ /// Views on the derivative of primary species mobile aggregate concentration wrt log of primary concentration
+ ElementViewConst< arrayView4d< real64 const, constitutive::reactivefluid::USD_SPECIES_DC > > const m_dPrimarySpeciesMobileAggregateConc_dLogPrimaryConc;
+
+ /// Array of flags to indicate mobile primary species
+ arrayView1d< integer const > const m_mobilePrimarySpeciesFlags;
+
+};
+
+
+/**
+ * @class DirichletFluxComputeKernelFactory
+ */
+class DirichletFluxComputeKernelFactory
+{
+public:
+
+ /**
+ * @brief Create a new kernel and launch
+ * @tparam POLICY the policy used in the RAJA kernel
+ * @param[in] numSpecies the number of primary species
+ * @param[in] mobilePrimarySpeciesFlags the array of flags to indicate mobile primary species
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] dofKey string to get the element degrees of freedom numbers
+ * @param[in] solverName name of the solver (to name accessors)
+ * @param[in] faceManager reference to the face manager
+ * @param[in] elemManager reference to the element region manager
+ * @param[in] stencilWrapper reference to the boundary stencil wrapper
+ * @param[in] reactiveFluid the single phase reactive fluid constitutive model
+ * @param[in] dt time step size
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
+ template< typename POLICY >
+ static void
+ createAndLaunch( integer const numSpecies,
+ arrayView1d< integer const > const mobilePrimarySpeciesFlags,
+ globalIndex const rankOffset,
+ string const & dofKey,
+ string const & solverName,
+ FaceManager const & faceManager,
+ ElementRegionManager const & elemManager,
+ BoundaryStencilWrapper const & stencilWrapper,
+ constitutive::reactivefluid::ReactiveCompressibleSinglePhaseFluid & reactiveFluid,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ constitutiveUpdatePassThru( reactiveFluid, [&]( auto & fluid )
+ {
+ using FluidType = TYPEOFREF( fluid );
+ typename FluidType::KernelWrapper fluidWrapper = fluid.createKernelWrapper();
+
+ singlePhaseReactiveBaseKernels::internal::kernelLaunchSelectorCompSwitch( numSpecies, [&]( auto NS )
+ {
+ integer constexpr NUM_SPECIES = NS();
+ integer constexpr NUM_DOF = 1+NS();
+ integer constexpr NUM_EQN = 1+NS();
+
+ using kernelType = DirichletFluxComputeKernel< NUM_SPECIES, NUM_EQN, NUM_DOF, typename FluidType::KernelWrapper,
+ constitutive::CompressibleSinglePhaseFluid >;
+
+ ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor =
+ elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey );
+
+ dofNumberAccessor.setName( solverName + "/accessors/" + dofKey );
+
+ typename kernelType::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName );
+ typename kernelType::ReactiveSinglePhaseFlowAccessors reactiveFlowAccessors( elemManager, solverName );
+ typename kernelType::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName );
+ typename kernelType::ReactiveSinglePhaseFluidAccessors reactiveFluidAccessors( elemManager, solverName );
+ typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName );
+
+ kernelType kernel( rankOffset,
+ faceManager,
+ stencilWrapper,
+ fluidWrapper,
+ dofNumberAccessor,
+ singlePhaseFlowAccessors,
+ reactiveFlowAccessors,
+ singlePhaseFluidAccessors,
+ reactiveFluidAccessors,
+ permeabilityAccessors,
+ mobilePrimarySpeciesFlags,
+ dt,
+ localMatrix,
+ localRhs );
+
+ kernelType::template launch< POLICY >( stencilWrapper.size(), kernel );
+ } );
+ } );
+ }
+
+};
+
+} // namespace singlePhaseReactiveFVMKernels
+
+} // namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_DIRICHLETFLUXCOMPUTEKERNEL_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/FluidUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/FluidUpdateKernel.hpp
new file mode 100644
index 00000000000..3e9e79b6a4d
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/FluidUpdateKernel.hpp
@@ -0,0 +1,56 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 FluidUpdateKernel.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_FLUIDUPDATEKERNEL_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_FLUIDUPDATEKERNEL_HPP
+
+#include "common/DataTypes.hpp"
+#include "common/GEOS_RAJA_Interface.hpp"
+
+namespace geos
+{
+
+namespace singlePhaseReactiveBaseKernels
+{
+
+/******************************** FluidUpdateKernel ********************************/
+
+struct FluidUpdateKernel
+{
+ template< typename FLUID_WRAPPER >
+ static void launch( FLUID_WRAPPER const & fluidWrapper,
+ arrayView1d< real64 const > const & pres,
+ arrayView1d< real64 const > const & temp,
+ arrayView2d< real64 const, compflow::USD_COMP > const logPrimaryConc )
+ {
+ forAll< parallelDevicePolicy<> >( fluidWrapper.numElems(), [=] GEOS_HOST_DEVICE ( localIndex const k )
+ {
+ for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q )
+ {
+ fluidWrapper.update( k, q, pres[k], temp[k], logPrimaryConc[k] );
+ }
+ } );
+ }
+};
+
+} // namespace singlePhaseReactiveBaseKernels
+
+} // namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_FLUIDUPDATEKERNEL_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/FluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/FluxComputeKernel.hpp
new file mode 100644
index 00000000000..a408c29aa0d
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/FluxComputeKernel.hpp
@@ -0,0 +1,574 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 FluxComputeKernel.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_FLUXCOMPUTEKERNEL_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_FLUXCOMPUTEKERNEL_HPP
+
+#include "constitutive/diffusion/DiffusionFields.hpp"
+#include "constitutive/diffusion/DiffusionBase.hpp"
+#include "constitutive/solid/porosity/PorosityBase.hpp"
+#include "constitutive/solid/porosity/PorosityFields.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveSinglePhaseFluid.hpp"
+#include "constitutive/fluid/reactivefluid/ReactiveFluidFields.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp"
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/KernelLaunchSelectors.hpp"
+
+
+namespace geos
+{
+
+namespace singlePhaseReactiveFVMKernels
+{
+
+/**
+ * @class FluxComputeKernel
+ * @tparam NUM_SPECIES number of fluid primary species
+ * @tparam NUM_EQN number of equations
+ * @tparam NUM_DOF number of degrees of freedom
+ * @tparam STENCILWRAPPER the type of the stencil wrapper
+ * @tparam BASE_FLUID_TYPE the type of the base model for the reactive fluid model
+ * @brief Define the interface for the assembly kernel in charge of flux terms
+ */
+template< integer NUM_SPECIES, integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER, typename BASE_FLUID_TYPE >
+class FluxComputeKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >
+{
+public:
+
+ /// Compile time value for the number of primary species
+ static constexpr integer numSpecies = NUM_SPECIES;
+
+ /// Number of flux support points (hard-coded for TFPA)
+ static constexpr integer numFluxSupportPoints = 2;
+
+ /**
+ * @brief The type for element-based data. Consists entirely of ArrayView's.
+ *
+ * Can be converted from ElementRegionManager::ElementViewConstAccessor
+ * by calling .toView() or .toViewConst() on an accessor instance
+ */
+ template< typename VIEWTYPE >
+ using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >;
+
+ using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase;
+ using DofNumberAccessor = AbstractBase::DofNumberAccessor;
+ using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors;
+ using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors;
+ using PermeabilityAccessors = AbstractBase::PermeabilityAccessors;
+
+ using AbstractBase::m_dt;
+ using AbstractBase::m_rankOffset;
+ using AbstractBase::m_dofNumber;
+ using AbstractBase::m_gravCoef;
+ using AbstractBase::m_mob;
+ using AbstractBase::m_dens;
+ using AbstractBase::m_dDens;
+
+ using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >;
+ using Base::numDof;
+ using Base::numEqn;
+ using Base::maxNumElems;
+ using Base::maxNumConns;
+ using Base::maxStencilSize;
+ using Base::m_stencilWrapper;
+ using Base::m_seri;
+ using Base::m_sesri;
+ using Base::m_sei;
+
+ using ReactiveSinglePhaseFlowAccessors =
+ StencilAccessors< fields::flow::logPrimarySpeciesConcentration,
+ fields::flow::dMobility_dLogPrimaryConc >;
+
+ using ReactiveSinglePhaseFluidAccessors =
+ StencilMaterialAccessors< constitutive::reactivefluid::ReactiveSinglePhaseFluid< BASE_FLUID_TYPE >,
+ fields::reactivefluid::primarySpeciesMobileAggregateConcentration,
+ fields::reactivefluid::dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations >;
+
+ using DiffusionAccessors =
+ StencilMaterialAccessors< constitutive::DiffusionBase,
+ fields::diffusion::diffusivity,
+ fields::diffusion::dDiffusivity_dTemperature >;
+
+ using PorosityAccessors =
+ StencilMaterialAccessors< constitutive::PorosityBase,
+ fields::porosity::referencePorosity >;
+
+ /**
+ * @brief Constructor for the kernel interface
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] stencilWrapper reference to the stencil wrapper
+ * @param[in] dofNumberAccessor
+ * @param[in] singlePhaseFlowAccessors
+ * @param[in] reactiveSinglePhaseFlowAccessors
+ * @param[in] singlePhaseFluidAccessors
+ * @param[in] reactiveSinglePhaseFluidAccessors
+ * @param[in] permeabilityAccessors
+ * @param[in] diffusionAccessors
+ * @param[in] porosityAccessors
+ * @param[in] hasDiffusion the flag to turn on diffusion calculation
+ * @param[in] mobilePrimarySpeciesFlags the array of flags to indicate mobile primary species
+ * @param[in] dt time step size
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
+ FluxComputeKernel( globalIndex const rankOffset,
+ STENCILWRAPPER const & stencilWrapper,
+ DofNumberAccessor const & dofNumberAccessor,
+ SinglePhaseFlowAccessors const & singlePhaseFlowAccessors,
+ ReactiveSinglePhaseFlowAccessors const & reactiveSinglePhaseFlowAccessors,
+ SinglePhaseFluidAccessors const & singlePhaseFluidAccessors,
+ ReactiveSinglePhaseFluidAccessors const & reactiveSinglePhaseFluidAccessors,
+ PermeabilityAccessors const & permeabilityAccessors,
+ DiffusionAccessors const & diffusionAccessors,
+ PorosityAccessors const & porosityAccessors,
+ integer const & hasDiffusion,
+ arrayView1d< integer const > const & mobilePrimarySpeciesFlags,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ : Base( rankOffset,
+ stencilWrapper,
+ dofNumberAccessor,
+ singlePhaseFlowAccessors,
+ singlePhaseFluidAccessors,
+ permeabilityAccessors,
+ dt,
+ localMatrix,
+ localRhs ),
+ m_logPrimarySpeciesConc( reactiveSinglePhaseFlowAccessors.get( fields::flow::logPrimarySpeciesConcentration {} ) ),
+ m_dMob_dLogPrimaryConc( reactiveSinglePhaseFlowAccessors.get( fields::flow::dMobility_dLogPrimaryConc {} ) ),
+ m_primarySpeciesMobileAggregateConc( reactiveSinglePhaseFluidAccessors.get( fields::reactivefluid::primarySpeciesMobileAggregateConcentration {} ) ),
+ m_dPrimarySpeciesMobileAggregateConc_dLogPrimaryConc( reactiveSinglePhaseFluidAccessors.get(
+ fields::reactivefluid::dPrimarySpeciesMobileAggregateConcentration_dLogPrimarySpeciesConcentrations {} ) ),
+ m_diffusivity( diffusionAccessors.get( fields::diffusion::diffusivity {} ) ),
+ m_dDiffusivity_dTemp( diffusionAccessors.get( fields::diffusion::dDiffusivity_dTemperature {} ) ),
+ m_referencePorosity( porosityAccessors.get( fields::porosity::referencePorosity {} ) ),
+ m_hasDiffusion( hasDiffusion ),
+ m_mobilePrimarySpeciesFlags( mobilePrimarySpeciesFlags )
+ {}
+
+ /**
+ * @struct StackVariables
+ * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack
+ */
+ struct StackVariables : public Base::StackVariables
+ {
+public:
+
+ /**
+ * @brief Constructor for the stack variables
+ * @param[in] size size of the stencil for this connection
+ * @param[in] numElems number of elements for this connection
+ */
+ GEOS_HOST_DEVICE
+ StackVariables( localIndex const size, localIndex numElems )
+ : Base::StackVariables( size, numElems )
+ {}
+
+ using Base::StackVariables::stencilSize;
+ using Base::StackVariables::numFluxElems;
+ using Base::StackVariables::transmissibility;
+ using Base::StackVariables::dTrans_dPres;
+ using Base::StackVariables::dofColIndices;
+ using Base::StackVariables::localFlux;
+ using Base::StackVariables::localFluxJacobian;
+
+ /// Diffusion transmissibility
+ real64 diffusionTransmissibility[maxNumConns][numFluxSupportPoints]{};
+ /// Derivatives of diffusion transmissibility with respect to temperature
+ real64 dDiffusionTrans_dT[maxNumConns][numFluxSupportPoints]{};
+
+ };
+
+ /**
+ * @brief Compute the local flux contributions to the residual and Jacobian
+ * @tparam FUNC the type of the function that can be used to customize the computation of the flux
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ * @param[in] NoOpFunc the function used to customize the computation of the flux
+ */
+ template< typename FUNC = NoOpFunc >
+ GEOS_HOST_DEVICE
+ void computeFlux( localIndex const iconn,
+ StackVariables & stack,
+ FUNC && kernelOp = NoOpFunc{} ) const
+ {
+ using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< 1 >;
+ // ***********************************************
+ // First, we call the base computeFlux to compute:
+ // 1) massFlux and its derivatives,
+ // 2) speciesFlux and its derivatives
+ Base::computeFlux( iconn, stack, [&] ( localIndex const (&k)[2],
+ localIndex const (&seri)[2],
+ localIndex const (&sesri)[2],
+ localIndex const (&sei)[2],
+ localIndex const connectionIndex,
+ real64 const alpha,
+ real64 const mobility,
+ real64 const & potGrad,
+ real64 const & fluxVal,
+ real64 const (&dFlux_dP)[2] )
+ {
+ // Step 1: compute the derivatives of the fluid density, potential difference,
+ // and the massFlux wrt log of primary species concentration (to complete)
+ real64 dFlux_dLogConc[numFluxSupportPoints][numSpecies]{};
+
+ GEOS_UNUSED_VAR( dFlux_dLogConc ); // Todo: to add the massFlux derivatives wrt speciesConc
+
+ // Step 2: compute the speciesFlux
+ real64 speciesFlux[numSpecies]{};
+ real64 dSpeciesFlux_dP[numFluxSupportPoints][numSpecies]{};
+ real64 dSpeciesFlux_dLogConc[numFluxSupportPoints][numSpecies][numSpecies]{};
+ // real64 dSpeciesFlux_dTrans[numSpecies]{};
+
+ // choose upstream cell
+ localIndex const k_up = (potGrad >= 0) ? 0 : 1;
+
+ localIndex const er_up = seri[k_up];
+ localIndex const esr_up = sesri[k_up];
+ localIndex const ei_up = sei[k_up];
+
+ real64 const fluidDens_up = m_dens[er_up][esr_up][ei_up][0];
+ real64 const dDens_dPres = m_dDens[er_up][esr_up][ei_up][0][DerivOffset::dP];
+
+ // compute species fluxes and derivatives using upstream cell concentration
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ real64 const aggregateConc_i = m_primarySpeciesMobileAggregateConc[er_up][esr_up][ei_up][0][is];
+ speciesFlux[is] = aggregateConc_i / fluidDens_up * fluxVal;
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ dSpeciesFlux_dP[ke][is] += aggregateConc_i / fluidDens_up * dFlux_dP[ke];
+ }
+
+ dSpeciesFlux_dP[k_up][is] += -aggregateConc_i * fluxVal * dDens_dPres / (fluidDens_up * fluidDens_up);
+
+ for( integer js = 0; js < numSpecies; ++js )
+ {
+ real64 const dAggregateConc_i_dLogConc_j = m_dPrimarySpeciesMobileAggregateConc_dLogPrimaryConc[er_up][esr_up][ei_up][0][is][js];
+ dSpeciesFlux_dLogConc[k_up][is][js] += dAggregateConc_i_dLogConc_j / fluidDens_up * fluxVal;
+ }
+ }
+
+ /// populate local flux vector and derivatives
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ integer const eqIndex0 = k[0] * numEqn + numEqn - numSpecies + is;
+ integer const eqIndex1 = k[1] * numEqn + numEqn - numSpecies + is;
+
+ stack.localFlux[eqIndex0] += m_dt * speciesFlux[is] * m_mobilePrimarySpeciesFlags[is];
+ stack.localFlux[eqIndex1] -= m_dt * speciesFlux[is] * m_mobilePrimarySpeciesFlags[is];
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ localIndex const localDofIndexPres = k[ke] * numDof;
+ stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dSpeciesFlux_dP[ke][is] * m_mobilePrimarySpeciesFlags[is];
+ stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dSpeciesFlux_dP[ke][is] * m_mobilePrimarySpeciesFlags[is];
+
+ for( integer js = 0; js < numSpecies; ++js )
+ {
+ localIndex const localDofIndexSpecies = localDofIndexPres + js + numDof - numSpecies;
+ stack.localFluxJacobian[eqIndex0][localDofIndexSpecies] += m_dt * dSpeciesFlux_dLogConc[ke][is][js] * m_mobilePrimarySpeciesFlags[is];
+ stack.localFluxJacobian[eqIndex1][localDofIndexSpecies] -= m_dt * dSpeciesFlux_dLogConc[ke][is][js] * m_mobilePrimarySpeciesFlags[is];
+ }
+ }
+ }
+
+ // Customize the kernel with this lambda
+ kernelOp( k, seri, sesri, sei, connectionIndex, alpha, mobility, potGrad, fluxVal, dFlux_dP, fluidDens_up );
+ } );
+ }
+
+ /**
+ * @brief Compute the local diffusion contributions to the residual and Jacobian
+ * @tparam FUNC the type of the function that can be used to customize the computation of the flux
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ * @param[in] NoOpFunc the function used to customize the computation of the flux
+ */
+ template< typename FUNC = NoOpFunc >
+ GEOS_HOST_DEVICE
+ void computeDiffusion( localIndex const iconn,
+ StackVariables & stack,
+ FUNC && kernelOp = NoOpFunc{} ) const
+ {
+ if( m_hasDiffusion )
+ {
+ // *****************************************************
+ // Computation of the diffusion term in the species flux
+
+ // Step 1: compute the diffusion transmissibilities at this face
+ m_stencilWrapper.computeWeights( iconn,
+ m_diffusivity,
+ m_dDiffusivity_dTemp,
+ stack.diffusionTransmissibility,
+ stack.dDiffusionTrans_dT );
+
+ localIndex k[numFluxSupportPoints]{};
+ localIndex connectionIndex = 0;
+
+ for( k[0] = 0; k[0] < stack.numFluxElems; ++k[0] )
+ {
+ for( k[1] = k[0] + 1; k[1] < stack.numFluxElems; ++k[1] )
+ {
+ localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )};
+ localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )};
+ localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )};
+
+ // clear working arrays
+ real64 diffusionFlux[numSpecies]{};
+ real64 speciesGrad[numSpecies]{};
+ // real64 dDiffusionFlux_dP[numFluxSupportPoints][numSpecies]{}; // Turn on if diffusionFlux is pressure-dependent
+ real64 dDiffusionFlux_dLogConc[numFluxSupportPoints][numSpecies][numSpecies]{};
+
+ real64 const diffusionTrans[numFluxSupportPoints] = { stack.diffusionTransmissibility[connectionIndex][0],
+ stack.diffusionTransmissibility[connectionIndex][1] };
+
+ //***** calculation of flux *****
+ // loop over primary species
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ // real64 dSpeciesGrad_i_dP[numFluxSupportPoints]{}; // Turn on if speciesGrad is pressure-dependent
+ real64 dSpeciesGrad_i_dLogConc[numFluxSupportPoints][numSpecies]{};
+
+ // Step 2: compute species gradient
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ localIndex const er = seri[ke];
+ localIndex const esr = sesri[ke];
+ localIndex const ei = sei[ke];
+
+ real64 const aggregateConc_i = m_primarySpeciesMobileAggregateConc[er][esr][ei][0][is];
+
+ speciesGrad[is] += diffusionTrans[ke] * aggregateConc_i;
+
+ for( integer js = 0; js < numSpecies; ++js )
+ {
+ real64 const dAggregateConc_i_dLogConc_j = m_dPrimarySpeciesMobileAggregateConc_dLogPrimaryConc[er][esr][ei][0][is][js];
+
+ dSpeciesGrad_i_dLogConc[ke][js] += diffusionTrans[ke] * dAggregateConc_i_dLogConc_j;
+ }
+ }
+
+ // choose upstream cell for species upwinding
+ localIndex const k_up = (speciesGrad[is] >= 0) ? 0 : 1;
+
+ localIndex const er_up = seri[k_up];
+ localIndex const esr_up = sesri[k_up];
+ localIndex const ei_up = sei[k_up];
+
+ // computation of the upwinded species flux
+ diffusionFlux[is] += m_referencePorosity[er_up][esr_up][ei_up] * speciesGrad[is];
+
+ // add contributions of the derivatives of component fractions wrt pressure/component fractions
+ for( integer ke = 0; ke < numFluxSupportPoints; ke++ )
+ {
+ for( integer js = 0; js < numSpecies; ++js )
+ {
+ dDiffusionFlux_dLogConc[ke][is][js] += m_referencePorosity[er_up][esr_up][ei_up] * dSpeciesGrad_i_dLogConc[ke][js];
+ }
+ }
+
+ // Add the local diffusion flux contribution to the residual and Jacobian
+ integer const eqIndex0 = k[0] * numEqn + numEqn - numSpecies + is;
+ integer const eqIndex1 = k[1] * numEqn + numEqn - numSpecies + is;
+
+ stack.localFlux[eqIndex0] += m_dt * diffusionFlux[is] * m_mobilePrimarySpeciesFlags[is];
+ stack.localFlux[eqIndex1] -= m_dt * diffusionFlux[is] * m_mobilePrimarySpeciesFlags[is];
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ localIndex const localDofIndexPres = k[ke] * numDof;
+ // stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dDiffusionFlux_dP[ke][is] * m_mobilePrimarySpeciesFlags[is];
+ // stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dDiffusionFlux_dP[ke][is] * m_mobilePrimarySpeciesFlags[is];
+
+ for( integer js = 0; js < numSpecies; ++js )
+ {
+ localIndex const localDofIndexSpecies = localDofIndexPres + js + numDof - numSpecies;
+ stack.localFluxJacobian[eqIndex0][localDofIndexSpecies] += m_dt * dDiffusionFlux_dLogConc[ke][is][js] * m_mobilePrimarySpeciesFlags[is];
+ stack.localFluxJacobian[eqIndex1][localDofIndexSpecies] -= m_dt * dDiffusionFlux_dLogConc[ke][is][js] * m_mobilePrimarySpeciesFlags[is];
+ }
+ }
+
+ // Customize the kernel with this lambda
+ kernelOp( is, k, seri, sesri, sei, connectionIndex, k_up );
+ } // loop over primary species
+ connectionIndex++;
+ }
+ }
+ }
+ }
+
+ /**
+ * @brief Performs the complete phase for the kernel.
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ */
+ template< typename FUNC = NoOpFunc >
+ GEOS_HOST_DEVICE
+ void complete( localIndex const iconn,
+ StackVariables & stack,
+ FUNC && kernelOp = NoOpFunc{} ) const
+ {
+ // Call Base::complete to assemble the total mass balance equation
+ // In the lambda, add contribution to residual and jacobian into the species amount balance equation
+ Base::complete( iconn, stack, [&] ( integer const i,
+ localIndex const localRow )
+ {
+ // The no. of fluxes is equal to the no. of equations in m_localRhs and m_localMatrix
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn - numSpecies + is],
+ stack.localFlux[i * numEqn + numEqn - numSpecies + is] );
+ AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >
+ ( localRow + numEqn - numSpecies + is,
+ stack.dofColIndices.data(),
+ stack.localFluxJacobian[i * numEqn + numEqn - numSpecies + is].dataIfContiguous(),
+ stack.stencilSize * numDof );
+ }
+
+ // call the lambda to assemble additional terms, such as thermal terms
+ kernelOp( i, localRow );
+ } );
+ }
+
+ /**
+ * @brief Performs the kernel launch
+ * @tparam POLICY the policy used in the RAJA kernels
+ * @tparam KERNEL_TYPE the kernel type
+ * @param[in] numConnections the number of connections
+ * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables
+ */
+ template< typename POLICY, typename KERNEL_TYPE >
+ static void
+ launch( localIndex const numConnections,
+ KERNEL_TYPE const & kernelComponent )
+ {
+ GEOS_MARK_FUNCTION;
+
+ forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn )
+ {
+ typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ),
+ kernelComponent.numPointsInFlux( iconn ) );
+
+ kernelComponent.setup( iconn, stack );
+ kernelComponent.computeFlux( iconn, stack );
+ kernelComponent.computeDiffusion( iconn, stack );
+ kernelComponent.complete( iconn, stack );
+ } );
+ }
+
+protected:
+
+ /// Views on log of primary species concentration
+ ElementViewConst< arrayView2d< real64 const, compflow::USD_COMP > > const m_logPrimarySpeciesConc;
+
+ /// Views on derivatives of fluid mobilities
+ ElementViewConst< arrayView2d< real64 const, compflow::USD_FLUID_DC > > const m_dMob_dLogPrimaryConc;
+
+ /// Views on primary species aggregate concentration
+ ElementViewConst< arrayView3d< real64 const, constitutive::reactivefluid::USD_SPECIES > > const m_primarySpeciesMobileAggregateConc;
+
+ /// Views on the derivative of primary species mobile aggregate concentration wrt log of primary concentration
+ ElementViewConst< arrayView4d< real64 const, constitutive::reactivefluid::USD_SPECIES_DC > > const m_dPrimarySpeciesMobileAggregateConc_dLogPrimaryConc;
+
+ /// Views on diffusivity
+ ElementViewConst< arrayView3d< real64 const > > const m_diffusivity;
+ ElementViewConst< arrayView3d< real64 const > > const m_dDiffusivity_dTemp;
+
+ /// View on the reference porosity
+ ElementViewConst< arrayView1d< real64 const > > const m_referencePorosity;
+
+ /// Flag of adding the diffusion term
+ integer const m_hasDiffusion;
+
+ /// Array of flags to indicate mobile primary species
+ arrayView1d< integer const > const m_mobilePrimarySpeciesFlags;
+};
+
+/**
+ * @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] numSpecies the number of primary species
+ * @param[in] hasDiffusion the flag of adding diffusion term
+ * @param[in] mobilePrimarySpeciesFlags the array of flags to indicate mobile primary species
+ * @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 numSpecies,
+ integer const hasDiffusion,
+ arrayView1d< integer const > const mobilePrimarySpeciesFlags,
+ globalIndex const rankOffset,
+ string const & dofKey,
+ string const & solverName,
+ ElementRegionManager const & elemManager,
+ STENCILWRAPPER const & stencilWrapper,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ singlePhaseReactiveBaseKernels::internal::kernelLaunchSelectorCompSwitch( numSpecies, [&]( auto NS )
+ {
+ integer constexpr NUM_SPECIES = NS();
+ integer constexpr NUM_DOF = 1+NS();
+ integer constexpr NUM_EQN = 1+NS();
+
+ ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor =
+ elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey );
+ dofNumberAccessor.setName( solverName + "/accessors/" + dofKey );
+
+ using KernelType = FluxComputeKernel< NUM_SPECIES, NUM_EQN, NUM_DOF, STENCILWRAPPER, constitutive::CompressibleSinglePhaseFluid >;
+ typename KernelType::SinglePhaseFlowAccessors flowAccessors( elemManager, solverName );
+ typename KernelType::ReactiveSinglePhaseFlowAccessors reactiveFlowAccessors( elemManager, solverName );
+ typename KernelType::SinglePhaseFluidAccessors fluidAccessors( elemManager, solverName );
+ typename KernelType::ReactiveSinglePhaseFluidAccessors reactiveFluidAccessors( elemManager, solverName );
+ typename KernelType::PermeabilityAccessors permAccessors( elemManager, solverName );
+ typename KernelType::DiffusionAccessors diffusionAccessors( elemManager, solverName );
+ typename KernelType::PorosityAccessors porosityAccessors( elemManager, solverName );
+
+ KernelType kernel( rankOffset, stencilWrapper, dofNumberAccessor,
+ flowAccessors, reactiveFlowAccessors, fluidAccessors, reactiveFluidAccessors,
+ permAccessors, diffusionAccessors, porosityAccessors, hasDiffusion, mobilePrimarySpeciesFlags,
+ dt, localMatrix, localRhs );
+ KernelType::template launch< POLICY >( stencilWrapper.size(), kernel );
+ } );
+ }
+};
+
+} // namespace singlePhaseReactiveFVMKernels
+
+} // namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_FLUXCOMPUTEKERNEL_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/KernelLaunchSelectors.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/KernelLaunchSelectors.hpp
new file mode 100644
index 00000000000..8964b9b6ef0
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/KernelLaunchSelectors.hpp
@@ -0,0 +1,77 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 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 KernelLaunchSelector.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_KERNELLAUNCHSELECTOR_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_KERNELLAUNCHSELECTOR_HPP
+
+#include "physicsSolvers/KernelLaunchSelectors.hpp"
+#include "codingUtilities/Utilities.hpp"
+#include "common/DataLayouts.hpp"
+#include "common/DataTypes.hpp"
+#include "common/GEOS_RAJA_Interface.hpp"
+
+namespace geos
+{
+
+namespace singlePhaseReactiveBaseKernels
+{
+
+/******************************** Kernel launch machinery ********************************/
+
+namespace internal
+{
+
+template< typename T, typename LAMBDA >
+void kernelLaunchSelectorCompSwitch( T value, LAMBDA && lambda )
+{
+ static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: type should be integral" );
+
+ switch( value )
+ {
+ case 1:
+ { lambda( std::integral_constant< T, 1 >() ); return; }
+ case 2:
+ { lambda( std::integral_constant< T, 2 >() ); return; }
+ case 3:
+ { lambda( std::integral_constant< T, 3 >() ); return; }
+ case 4:
+ { lambda( std::integral_constant< T, 4 >() ); return; }
+ case 5:
+ { lambda( std::integral_constant< T, 5 >() ); return; }
+ case 6:
+ { lambda( std::integral_constant< T, 6 >() ); return; }
+ case 7:
+ { lambda( std::integral_constant< T, 7 >() ); return; }
+ case 8:
+ { lambda( std::integral_constant< T, 8 >() ); return; }
+ case 9:
+ { lambda( std::integral_constant< T, 9 >() ); return; }
+ default:
+ { GEOS_ERROR( "Unsupported number of primary species: " << value ); }
+ }
+}
+
+} // namespace internal
+
+} // namespace singlePhaseReactiveBaseKernels
+
+} // namespace geos
+
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_KERNELLAUNCHSELECTOR_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ReactionUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ReactionUpdateKernel.hpp
new file mode 100644
index 00000000000..79496d888fe
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ReactionUpdateKernel.hpp
@@ -0,0 +1,100 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ReactionUpdateKernel.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_REACTIONUPDATEKERNEL_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_REACTIONUPDATEKERNEL_HPP
+
+#include "common/DataTypes.hpp"
+#include "common/GEOS_RAJA_Interface.hpp"
+
+#include "constitutive/fluid/reactivefluid/ReactiveFluidLayouts.hpp"
+
+namespace geos
+{
+
+namespace singlePhaseReactiveBaseKernels
+{
+
+/******************************** EquilibriumReactionUpdateKernel ********************************/
+
+struct EquilibriumReactionUpdateKernel
+{
+
+ template< typename REACTION_WRAPPER_TYPE >
+ static void helper( REACTION_WRAPPER_TYPE const & reactionWrapper,
+ arrayView1d< real64 const > const & pres,
+ arrayView1d< real64 const > const & temp,
+ arrayView2d< real64, compflow::USD_COMP > const logPrimaryConc )
+ {
+ forAll< parallelDevicePolicy<> >( reactionWrapper.numElems(), [=] GEOS_HOST_DEVICE ( localIndex const k )
+ {
+ reactionWrapper.updateEquilibriumReaction( k, pres[k], temp[k], logPrimaryConc[k] );
+ } );
+ }
+
+ template< typename REACTIVE_FLUID >
+ static void launch( REACTIVE_FLUID const & fluid,
+ arrayView1d< real64 const > const & pres,
+ arrayView1d< real64 const > const & temp,
+ arrayView2d< real64, compflow::USD_COMP > const logPrimaryConc )
+ {
+ std::visit( [&]( auto const & reactionWrapper )
+ {
+ helper( reactionWrapper, pres, temp, logPrimaryConc );
+ }, fluid.createReactionKernelWrapper());
+ }
+};
+
+/******************************** MixedSystemReactionUpdateKernel ********************************/
+
+struct MixedSystemReactionUpdateKernel
+{
+
+ template< typename REACTION_WRAPPER_TYPE >
+ static void helper( REACTION_WRAPPER_TYPE const & reactionWrapper,
+ arrayView1d< real64 const > const & pres,
+ arrayView1d< real64 const > const & temp,
+ arrayView2d< real64 const, compflow::USD_COMP > const logPrimaryConc,
+ arrayView2d< real64 const, compflow::USD_COMP > const surfaceArea )
+ {
+ forAll< parallelDevicePolicy<> >( reactionWrapper.numElems(), [=] GEOS_HOST_DEVICE ( localIndex const k )
+ {
+ reactionWrapper.updateMixedReactionSystem( k, pres[k], temp[k], logPrimaryConc[k], surfaceArea[k] );
+ } );
+ }
+
+ template< typename REACTIVE_FLUID >
+ static void launch( REACTIVE_FLUID const & fluid,
+ arrayView1d< real64 const > const & pres,
+ arrayView1d< real64 const > const & temp,
+ arrayView2d< real64 const, compflow::USD_COMP > const logPrimaryConc,
+ arrayView2d< real64 const, compflow::USD_COMP > const surfaceArea )
+ {
+ std::visit( [&]( auto const & reactionWrapper )
+ {
+ helper( reactionWrapper, pres, temp, logPrimaryConc, surfaceArea );
+ }, fluid.createReactionKernelWrapper());
+ }
+};
+
+} // namespace singlePhaseReactiveBaseKernels
+
+} // namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_FLUIDUPDATEKERNEL_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ResidualNormKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ResidualNormKernel.hpp
new file mode 100644
index 00000000000..c9fc35acce1
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ResidualNormKernel.hpp
@@ -0,0 +1,331 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ResidualNormKernel.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_RESIDUALNORMKERNEL_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_RESIDUALNORMKERNEL_HPP
+
+#include "physicsSolvers/PhysicsSolverBaseKernels.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseReactiveTransportFields.hpp"
+
+namespace geos
+{
+
+namespace singlePhaseReactiveBaseKernels
+{
+
+/******************************** ResidualNormKernel ********************************/
+
+/**
+ * @class IsothermalResidualNormKernel
+ */
+class IsothermalResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 2 >
+{
+public:
+
+ using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 2 >;
+ using Base::m_minNormalizer;
+ using Base::m_rankOffset;
+ using Base::m_localResidual;
+ using Base::m_dofNumber;
+
+ IsothermalResidualNormKernel( globalIndex const rankOffset,
+ arrayView1d< real64 const > const & localResidual,
+ arrayView1d< globalIndex const > const & dofNumber,
+ arrayView1d< localIndex const > const & ghostRank,
+ integer const numPrimarySpecies,
+ ElementSubRegionBase const & subRegion,
+ real64 const minNormalizer )
+ : Base( rankOffset,
+ localResidual,
+ dofNumber,
+ ghostRank,
+ minNormalizer ),
+ m_numPrimarySpecies( numPrimarySpecies ),
+ m_mass_n( subRegion.template getField< fields::flow::mass_n >() ),
+ m_primarySpeciesAggregateMole_n( subRegion.getField< fields::flow::primarySpeciesAggregateMole_n >() )
+ {}
+
+ GEOS_HOST_DEVICE
+ virtual void computeLinf( localIndex const ei,
+ LinfStackVariables & stack ) const override
+ {
+ real64 const totalMassNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] );
+
+ // step 1: total mass residuals
+ real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow] ) / totalMassNormalizer;
+ if( valMass > stack.localValue[0] )
+ {
+ stack.localValue[0] = valMass;
+ }
+
+ // step 2: species amount residuals
+ for( integer idof = 0; idof < m_numPrimarySpecies; ++idof )
+ {
+ real64 const speciesAmountNormalizer = LvArray::math::max( m_minNormalizer, m_primarySpeciesAggregateMole_n[ei][idof] );
+ real64 const valAmount = LvArray::math::abs( m_localResidual[stack.localRow + idof + 1] ) / speciesAmountNormalizer;
+ if( valAmount > stack.localValue[1] )
+ {
+ stack.localValue[1] = valAmount;
+ }
+ }
+ }
+
+ GEOS_HOST_DEVICE
+ virtual void computeL2( localIndex const ei,
+ L2StackVariables & stack ) const override
+ {
+ real64 const totalMassNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] );
+
+ // step 1: total mass residuals
+ stack.localValue[0] += m_localResidual[stack.localRow] * m_localResidual[stack.localRow];
+ stack.localNormalizer[0] += totalMassNormalizer;
+
+ // step 2: species amount residuals
+ for( integer idof = 0; idof < m_numPrimarySpecies; ++idof )
+ {
+ real64 const speciesAmountNormalizer = LvArray::math::max( m_minNormalizer, m_primarySpeciesAggregateMole_n[ei][idof] );
+
+ stack.localValue[1] += m_localResidual[stack.localRow + idof + 1] * m_localResidual[stack.localRow + idof + 1];
+ stack.localNormalizer[1] += speciesAmountNormalizer;
+ }
+ }
+
+
+protected:
+
+ /// Number of primary species
+ integer const m_numPrimarySpecies;
+
+ /// View on mass at the previous converged time step
+ arrayView1d< real64 const > const m_mass_n;
+
+ // View on primary species aggregate amount (moles) from previous time step
+ arrayView2d< real64 const, compflow::USD_COMP > m_primarySpeciesAggregateMole_n;
+
+};
+
+/**
+ * @class ThermalResidualNormKernel
+ */
+class ThermalResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 3 >
+{
+public:
+
+ using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 3 >;
+ using Base::m_minNormalizer;
+ using Base::m_rankOffset;
+ using Base::m_localResidual;
+ using Base::m_dofNumber;
+
+ ThermalResidualNormKernel( globalIndex const rankOffset,
+ arrayView1d< real64 const > const & localResidual,
+ arrayView1d< globalIndex const > const & dofNumber,
+ arrayView1d< localIndex const > const & ghostRank,
+ integer const numPrimarySpecies,
+ ElementSubRegionBase const & subRegion,
+ real64 const minNormalizer )
+ : Base( rankOffset,
+ localResidual,
+ dofNumber,
+ ghostRank,
+ minNormalizer ),
+ m_numPrimarySpecies( numPrimarySpecies ),
+ m_mass_n( subRegion.template getField< fields::flow::mass_n >() ),
+ m_primarySpeciesAggregateMole_n( subRegion.getField< fields::flow::primarySpeciesAggregateMole_n >() ),
+ m_energy_n( subRegion.template getField< fields::flow::energy_n >() )
+ {}
+
+ GEOS_HOST_DEVICE
+ void computeMassEnergyNormalizers( localIndex const ei,
+ real64 & totalMassNormalizer,
+ real64 & energyNormalizer ) const
+ {
+ totalMassNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] );
+ energyNormalizer = LvArray::math::max( m_minNormalizer, LvArray::math::abs( m_energy_n[ei] ) ); // energy can be negative
+ }
+
+ GEOS_HOST_DEVICE
+ virtual void computeLinf( localIndex const ei,
+ LinfStackVariables & stack ) const override
+ {
+ real64 totalMassNormalizer = 0.0, energyNormalizer = 0.0;
+ computeMassEnergyNormalizers( ei, totalMassNormalizer, energyNormalizer );
+
+ // step 1: mass residual
+
+ real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow] ) / totalMassNormalizer;
+ if( valMass > stack.localValue[0] )
+ {
+ stack.localValue[0] = valMass;
+ }
+
+ // step 2: energy residual
+ real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + 1] ) / energyNormalizer;
+ if( valEnergy > stack.localValue[1] )
+ {
+ stack.localValue[1] = valEnergy;
+ }
+
+ // step 3: species amount residuals
+ for( integer idof = 0; idof < m_numPrimarySpecies; ++idof )
+ {
+ real64 const speciesAmountNormalizer = LvArray::math::max( m_minNormalizer, m_primarySpeciesAggregateMole_n[ei][idof] );
+ real64 const valAmount = LvArray::math::abs( m_localResidual[stack.localRow + idof + 2] ) / speciesAmountNormalizer;
+ if( valAmount > stack.localValue[2] )
+ {
+ stack.localValue[2] = valAmount;
+ }
+ }
+ }
+
+ GEOS_HOST_DEVICE
+ virtual void computeL2( localIndex const ei,
+ L2StackVariables & stack ) const override
+ {
+ real64 totalMassNormalizer = 0.0, energyNormalizer = 0.0;
+ computeMassEnergyNormalizers( ei, totalMassNormalizer, energyNormalizer );
+
+ // step 1: mass residual
+
+ stack.localValue[0] += m_localResidual[stack.localRow] * m_localResidual[stack.localRow];
+ stack.localNormalizer[0] += totalMassNormalizer;
+
+ // step 2: energy residual
+
+ stack.localValue[1] += m_localResidual[stack.localRow + 1] * m_localResidual[stack.localRow + 1];
+ stack.localNormalizer[1] += energyNormalizer;
+
+ // step 3: species amount residuals
+ for( integer idof = 0; idof < m_numPrimarySpecies; ++idof )
+ {
+ real64 const speciesAmountNormalizer = LvArray::math::max( m_minNormalizer, m_primarySpeciesAggregateMole_n[ei][idof] );
+
+ stack.localValue[2] += m_localResidual[stack.localRow + idof + 2] * m_localResidual[stack.localRow + idof + 2];
+ stack.localNormalizer[2] += speciesAmountNormalizer;
+ }
+ }
+
+
+protected:
+
+ /// Number of primary species
+ integer const m_numPrimarySpecies;
+
+ /// View on mass at the previous converged time step
+ arrayView1d< real64 const > const m_mass_n;
+
+ // View on primary species aggregate amount (moles) from previous time step
+ arrayView2d< real64 const, compflow::USD_COMP > m_primarySpeciesAggregateMole_n;
+
+ /// View on energy at the previous converged time step
+ arrayView1d< real64 const > const m_energy_n;
+
+};
+
+/**
+ * @class ResidualNormKernelFactory
+ */
+class ResidualNormKernelFactory
+{
+public:
+
+ /**
+ * @brief Create a new kernel and launch
+ * @tparam POLICY the policy used in the RAJA kernel
+ * @param[in] normType the type of norm used (Linf or L2)
+ * @param[in] numPrimarySpecies the number of primary species
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] dofKey the string key to retrieve the degress of freedom numbers
+ * @param[in] localResidual the residual vector on my MPI rank
+ * @param[in] subRegion the element subregion
+ * @param[out] residualNorm the residual norm on the subRegion
+ * @param[out] residualNormalizer the residual normalizer on the subRegion
+ */
+ template< typename POLICY >
+ static void
+ createAndLaunch( physicsSolverBaseKernels::NormType const normType,
+ integer const numPrimarySpecies,
+ globalIndex const rankOffset,
+ string const dofKey,
+ arrayView1d< real64 const > const & localResidual,
+ ElementSubRegionBase const & subRegion,
+ real64 const minNormalizer,
+ real64 (& residualNorm)[2],
+ real64 (& residualNormalizer)[2] )
+ {
+ arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey );
+ arrayView1d< integer const > const ghostRank = subRegion.ghostRank();
+
+ IsothermalResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, numPrimarySpecies, subRegion, minNormalizer );
+ if( normType == physicsSolverBaseKernels::NormType::Linf )
+ {
+ IsothermalResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm );
+ }
+ else // L2 norm
+ {
+ IsothermalResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer );
+ }
+ }
+
+ /**
+ * @brief Create a new kernel and launch (thermal version)
+ * @tparam POLICY the policy used in the RAJA kernel
+ * @param[in] normType the type of norm used (Linf or L2)
+ * @param[in] numPrimarySpecies the number of primary species
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] dofKey the string key to retrieve the degress of freedom numbers
+ * @param[in] localResidual the residual vector on my MPI rank
+ * @param[in] subRegion the element subregion
+ * @param[out] residualNorm the residual norm on the subRegion
+ * @param[out] residualNormalizer the residual normalizer on the subRegion
+ */
+ template< typename POLICY >
+ static void
+ createAndLaunch( physicsSolverBaseKernels::NormType const normType,
+ integer const numPrimarySpecies,
+ globalIndex const rankOffset,
+ string const & dofKey,
+ arrayView1d< real64 const > const & localResidual,
+ ElementSubRegionBase const & subRegion,
+ real64 const minNormalizer,
+ real64 (& residualNorm)[3],
+ real64 (& residualNormalizer)[3] )
+ {
+ arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey );
+ arrayView1d< integer const > const ghostRank = subRegion.ghostRank();
+
+ ThermalResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, numPrimarySpecies, subRegion, minNormalizer );
+ if( normType == physicsSolverBaseKernels::NormType::Linf )
+ {
+ ThermalResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm );
+ }
+ else // L2 norm
+ {
+ ThermalResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer );
+ }
+ }
+
+};
+
+} // namespace singlePhaseReactiveBaseKernels
+
+} // namespace geos
+
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_REACTIVE_RESIDUALNORMKERNEL_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalAccumulationKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalAccumulationKernels.hpp
new file mode 100644
index 00000000000..33fa2ac0f3b
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalAccumulationKernels.hpp
@@ -0,0 +1,259 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ThermalAccumulationKernels.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_THERMALACCUMULATIONKERNELS_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_THERMALACCUMULATIONKERNELS_HPP
+
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/AccumulationKernels.hpp"
+
+namespace geos
+{
+
+namespace thermalSinglePhaseReactiveBaseKernels
+{
+
+/******************************** AccumulationKernel ********************************/
+
+/**
+ * @class AccumulationKernel
+ * @brief Define the interface for the assembly kernel in charge of accumulation
+ */
+template< typename SUBREGION_TYPE, integer NUM_DOF, integer NUM_SPECIES, typename BASE_FLUID_TYPE >
+class AccumulationKernel : public singlePhaseReactiveBaseKernels::AccumulationKernel< SUBREGION_TYPE, NUM_DOF, NUM_SPECIES, BASE_FLUID_TYPE >
+{
+
+public:
+
+ using Base = singlePhaseReactiveBaseKernels::AccumulationKernel< SUBREGION_TYPE, NUM_DOF, NUM_SPECIES, BASE_FLUID_TYPE >;
+ using Base::numDof;
+ using Base::numEqn;
+ using Base::numSpecies;
+ using Base::m_rankOffset;
+ using Base::m_dofNumber;
+ using Base::m_elemGhostRank;
+ using Base::m_localMatrix;
+ using Base::m_localRhs;
+ using Base::m_dMass;
+ using Base::m_volume;
+ using Base::m_deltaVolume;
+ using Base::m_primarySpeciesAggregateConcentration;
+
+ /// Note: Derivative lineup only supports dP & dT, not component terms
+ using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< 1 >;
+ /**
+ * @brief Constructor
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] dofKey the string key to retrieve the degress of freedom numbers
+ * @param[in] subRegion the element subregion
+ * @param[in] fluid the fluid model
+ * @param[in] solid the solid model
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
+ AccumulationKernel( globalIndex const rankOffset,
+ string const dofKey,
+ SUBREGION_TYPE const & subRegion,
+ constitutive::reactivefluid::ReactiveSinglePhaseFluid< BASE_FLUID_TYPE > const & fluid,
+ constitutive::CoupledSolidBase const & solid,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ : Base( rankOffset, dofKey, subRegion, fluid, solid, dt, localMatrix, localRhs ),
+ m_energy( subRegion.template getField< fields::flow::energy >() ),
+ m_energy_n( subRegion.template getField< fields::flow::energy_n >() ),
+ m_dEnergy( subRegion.template getField< fields::flow::dEnergy >() ),
+ m_dPoro_dTemp( solid.getDporosity_dTemperature() )
+ // m_dPrimarySpeciesAggregateConcentration_dTemp( fluid.dPrimarySpeciesAggregateConcentration_dTemp() ),
+ // m_dPrimarySpeciesTotalKineticRate_dTemp( fluid.dPrimarySpeciesTotalKineticRate_dTemp() ),
+ {}
+
+ /**
+ * @struct StackVariables
+ * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack
+ */
+ struct StackVariables : public Base::StackVariables
+ {
+public:
+
+ GEOS_HOST_DEVICE
+ StackVariables()
+ : Base::StackVariables()
+ {}
+
+ using Base::StackVariables::localRow;
+ using Base::StackVariables::dofIndices;
+ using Base::StackVariables::localResidual;
+ using Base::StackVariables::localJacobian;
+ using Base::StackVariables::poreVolume;
+ using Base::StackVariables::dPoreVolume_dLogPrimaryConc;
+
+ // Pore volume information
+
+ /// Derivative of pore volume with respect to temperature
+ real64 dPoreVolume_dTemp = 0.0;
+ };
+
+ /**
+ * @brief Performs the setup phase for the kernel.
+ * @param[in] ei the element index
+ * @param[in] stack the stack variables
+ */
+ GEOS_HOST_DEVICE
+ void setup( localIndex const ei,
+ StackVariables & stack ) const
+ {
+ Base::setup( ei, stack );
+
+ stack.dPoreVolume_dTemp = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dTemp[ei][0];
+ }
+
+ /**
+ * @brief Compute the local accumulation contributions to the residual and Jacobian
+ * @param[in] ei the element index
+ * @param[inout] stack the stack variables
+ * @param[in] kernelOp the function used to customize the kernel
+ */
+ GEOS_HOST_DEVICE
+ void computeAccumulation( localIndex const ei,
+ StackVariables & stack ) const
+ {
+ Base::computeAccumulation( ei, stack );
+
+ // Step 1: assemble the derivatives of the mass balance equation w.r.t temperature
+ stack.localJacobian[0][numDof-numSpecies-1] = m_dMass[ei][DerivOffset::dT];
+
+ // Step 2: assemble the accumulation term of the energy equation
+ // Step 2.1: assemble the residual and derivatives wrt pressure and temperature
+ stack.localResidual[numEqn-numSpecies-1] = m_energy[ei] - m_energy_n[ei];
+ stack.localJacobian[numEqn-numSpecies-1][0] += m_dEnergy[ei][DerivOffset::dP];
+ stack.localJacobian[numEqn-numSpecies-1][numDof-numSpecies-1] += m_dEnergy[ei][DerivOffset::dT];
+
+ // Step 2.2: assemble the derivatives of the energy equation w.r.t log primary species concentration
+ // for( integer is = 0; is < numSpecies; ++is )
+ // {
+ // stack.localJacobian[numEqn-numSpecies-1][is+numDof-numSpecies] += stack.dPoreVolume_dLogPrimaryConc[is] * m_density[ei][0] *
+ // m_fluidInternalEnergy[ei][0]
+ // - stack.dPoreVolume_dLogPrimaryConc[is] *
+ // m_rockInternalEnergy[ei][0]
+ // + stack.poreVolume * m_dDensity_dLogPrimaryConc[ei][is] *
+ // m_fluidInternalEnergy[ei][0]
+ // + stack.poreVolume * m_density[ei][0] *
+ // m_dFluidInternalEnergy_dLogPrimaryConc[ei][is];
+ // }
+
+ // Step 3: assemble the derivatives of the species amount balance equation w.r.t temperature
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ // Drivative of primary species amount in pore volume wrt temperature
+ stack.localJacobian[is+numEqn-numSpecies][numDof-numSpecies-1] += stack.dPoreVolume_dTemp * m_primarySpeciesAggregateConcentration[ei][0][is]
+ /* + stack.poreVolume *
+ m_dPrimarySpeciesAggregateConcentration_dTemp[ei][is] */;
+ // // Derivative of reaction term wrt temperature
+ // stack.localJacobian[is+numEqn-numSpecies][numDof-numSpecies-1] -= m_dt * ( m_volume[ei] + m_deltaVolume[ei] ) *
+ // m_dPrimarySpeciesTotalKineticRate_dTemp[is];
+ }
+ }
+
+ /**
+ * @brief Performs the complete phase for the kernel.
+ * @param[in] ei the element index
+ * @param[inout] stack the stack variables
+ */
+ GEOS_HOST_DEVICE
+ void complete( localIndex const ei,
+ StackVariables & stack ) const
+ {
+ // Step 1: assemble the total mass balance equation (i = 0)
+ // and species amount balance equation (i = numEqn-numSpecies to i = numEqn-1)
+ Base::complete( ei, stack );
+
+ // Step 2: assemble the energy equation (i = numEqn-numSpecies-1)
+ m_localRhs[stack.localRow + numEqn-numSpecies-1] += stack.localResidual[numEqn-numSpecies-1];
+ m_localMatrix.template addToRow< serialAtomic >( stack.localRow + numEqn-numSpecies-1,
+ stack.dofIndices,
+ stack.localJacobian[numEqn-numSpecies-1],
+ numDof );
+ }
+
+protected:
+
+ /// View on energy
+ arrayView1d< real64 const > const m_energy;
+ arrayView1d< real64 const > const m_energy_n;
+ arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const m_dEnergy;
+
+ /// Views on the porosity derivative
+ arrayView2d< real64 const > const m_dPoro_dTemp;
+
+ // // View on the derivatives of aggregate concentration for the primary species wrt temperature
+ // arrayView2d< real64 const, compflow::USD_COMP > m_dPrimarySpeciesAggregateConcentration_dTemp;
+
+ // // View on the derivatives of total kinetic rate of primary species wrt temperature
+ // arrayView2d< real64 const, compflow::USD_COMP > m_dPrimarySpeciesTotalKineticRate_dTemp;
+
+};
+
+/**
+ * @class AccumulationKernelFactory
+ */
+class AccumulationKernelFactory
+{
+public:
+
+ /**
+ * @brief Create a new kernel and launch
+ * @tparam POLICY the policy used in the RAJA kernel
+ * @param[in] numSpecies the number of primary species
+ * @param[in] dt time step
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] dofKey the string key to retrieve the degress of freedom numbers
+ * @param[in] subRegion the element subregion
+ * @param[in] fluid the fluid model
+ * @param[in] solid the solid model
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
+ template< typename POLICY, typename SUBREGION_TYPE, typename BASE_FLUID_TYPE >
+ static void
+ createAndLaunch( integer const numSpecies,
+ real64 const dt,
+ globalIndex const rankOffset,
+ string const dofKey,
+ SUBREGION_TYPE const & subRegion,
+ constitutive::reactivefluid::ReactiveSinglePhaseFluid< BASE_FLUID_TYPE > const & fluid,
+ constitutive::CoupledSolidBase const & solid,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ singlePhaseReactiveBaseKernels::
+ internal::kernelLaunchSelectorCompSwitch( numSpecies, [&] ( auto NS )
+ {
+ integer constexpr NUM_SPECIES = NS();
+ integer constexpr NUM_DOF = 2+NS();
+ AccumulationKernel< SUBREGION_TYPE, NUM_DOF, NUM_SPECIES, BASE_FLUID_TYPE > kernel( rankOffset, dofKey, subRegion, fluid, solid, dt, localMatrix, localRhs );
+ AccumulationKernel< SUBREGION_TYPE, NUM_DOF, NUM_SPECIES, BASE_FLUID_TYPE >::template launch< POLICY >( subRegion.size(), kernel );
+ } );
+ }
+};
+
+} // namespace thermalSinglePhaseReactiveBaseKernels
+
+} // namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_THERMALACCUMULATIONKERNELS_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalDirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalDirichletFluxComputeKernel.hpp
new file mode 100644
index 00000000000..7a87bdfbc50
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalDirichletFluxComputeKernel.hpp
@@ -0,0 +1,410 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ThermalDirichletFluxComputeKernel.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP
+
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/DirichletFluxComputeKernel.hpp"
+
+#include "constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp"
+#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp"
+
+namespace geos
+{
+
+namespace thermalSinglePhaseReactiveFVMKernels
+{
+
+/******************************** DirichletFluxComputeKernel ********************************/
+
+/**
+ * @class DirichletFluxComputeKernel
+ * @tparam NUM_SPECIES number of fluid primary species
+ * @tparam NUM_EQN number of equations
+ * @tparam NUM_DOF number of degrees of freedom
+ * @tparam FLUIDWRAPPER the type of the fluid wrapper
+ * @tparam BASE_FLUID_TYPE the type of the base model for the reactive fluid model
+ * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms
+ */
+template< integer NUM_SPECIES, integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER, typename BASE_FLUID_TYPE >
+class DirichletFluxComputeKernel : public singlePhaseReactiveFVMKernels::DirichletFluxComputeKernel< NUM_SPECIES, NUM_EQN, NUM_DOF, FLUIDWRAPPER, BASE_FLUID_TYPE >
+{
+public:
+
+/**
+ * @brief The type for element-based data. Consists entirely of ArrayView's.
+ *
+ * Can be converted from ElementRegionManager::ElementViewConstAccessor
+ * by calling .toView() or .toViewConst() on an accessor instance
+ */
+
+ using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< 1 >;
+ template< typename VIEWTYPE >
+ using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >;
+
+ using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase;
+ using DofNumberAccessor = AbstractBase::DofNumberAccessor;
+ using PermeabilityAccessors = AbstractBase::PermeabilityAccessors;
+ using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors;
+ using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors;
+
+ using AbstractBase::m_dt;
+ using AbstractBase::m_rankOffset;
+ using AbstractBase::m_dofNumber;
+ using AbstractBase::m_ghostRank;
+ using AbstractBase::m_gravCoef;
+ using AbstractBase::m_mob;
+ using AbstractBase::m_pres;
+ using AbstractBase::m_permeability;
+ using AbstractBase::m_dPerm_dPres;
+ using AbstractBase::m_dDens;
+ using AbstractBase::m_dMob;
+
+ using Base = singlePhaseReactiveFVMKernels::DirichletFluxComputeKernel< NUM_SPECIES, NUM_EQN, NUM_DOF, FLUIDWRAPPER, BASE_FLUID_TYPE >;
+ using Base::numSpecies;
+ using Base::numDof;
+ using Base::numEqn;
+ using Base::m_stencilWrapper;
+ using Base::m_seri;
+ using Base::m_sesri;
+ using Base::m_sei;
+ using Base::m_facePres;
+ using Base::m_faceGravCoef;
+
+ using ReactiveSinglePhaseFlowAccessors = typename Base::ReactiveSinglePhaseFlowAccessors;
+ using ReactiveSinglePhaseFluidAccessors = typename Base::ReactiveSinglePhaseFluidAccessors;
+
+ using ThermalSinglePhaseFlowAccessors =
+ StencilAccessors< fields::flow::temperature >;
+
+ using ThermalReactiveSinglePhaseFluidAccessors =
+ StencilMaterialAccessors< constitutive::reactivefluid::ReactiveSinglePhaseFluid< BASE_FLUID_TYPE >,
+ fields::singlefluid::enthalpy,
+ fields::singlefluid::dEnthalpy >;
+
+ using ThermalConductivityAccessors =
+ StencilMaterialAccessors< constitutive::SinglePhaseThermalConductivityBase,
+ fields::thermalconductivity::effectiveConductivity,
+ fields::thermalconductivity::dEffectiveConductivity_dT >;
+
+ /**
+ * @brief Constructor for the kernel interface
+ * @param[in] rankOffset the offset of the MPI rank
+ * @param[in] faceManager the face manager
+ * @param[in] stencilWrapper reference to the stencil wrapper
+ * @param[in] fluidWrapper reference to the fluid wrapper
+ * @param[in] dofNumberAccessor the degree of freedom number accessor
+ * @param[in] singlePhaseFlowAccessors the single phase flow accessor
+ * @param[in] reactiveSinglePhaseFlowAccessors accessor for *reactive* wrappers registered by the solver
+ * @param[in] thermalSinglePhaseFlowAccessors accessor for *thermal* wrappers registered by the solver
+ * @param[in] singlePhaseFluidAccessors the single phase fluid accessor
+ * @param[in] reactiveSinglePhaseFluidAccessors accessor for *reactive* wrappers registered by the single fluid model
+ * @param[in] thermalReactiveSinglePhaseFluidAccessors accessor for *thermal reactive* wrappers registered by the single fluid model
+ * @param[in] permeabilityAccessors the permeability accessor
+ * @param[in] thermalConductivityAccessors the thermal conductivity accessor
+ * @param[in] mobilePrimarySpeciesFlags the array of flags to indicate mobile primary species
+ * @param[in] dt the time step size
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
+ DirichletFluxComputeKernel( globalIndex const rankOffset,
+ FaceManager const & faceManager,
+ BoundaryStencilWrapper const & stencilWrapper,
+ FLUIDWRAPPER const & fluidWrapper,
+ DofNumberAccessor const & dofNumberAccessor,
+ SinglePhaseFlowAccessors const & singlePhaseFlowAccessors,
+ ReactiveSinglePhaseFlowAccessors const & reactiveSinglePhaseFlowAccessors,
+ ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors,
+ SinglePhaseFluidAccessors const & singlePhaseFluidAccessors,
+ ReactiveSinglePhaseFluidAccessors const & reactiveSinglePhaseFluidAccessors,
+ ThermalReactiveSinglePhaseFluidAccessors const & thermalReactiveSinglePhaseFluidAccessors,
+ PermeabilityAccessors const & permeabilityAccessors,
+ ThermalConductivityAccessors const & thermalConductivityAccessors,
+ arrayView1d< integer const > const & mobilePrimarySpeciesFlags,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+
+ : Base( rankOffset,
+ faceManager,
+ stencilWrapper,
+ fluidWrapper,
+ dofNumberAccessor,
+ singlePhaseFlowAccessors,
+ reactiveSinglePhaseFlowAccessors,
+ singlePhaseFluidAccessors,
+ reactiveSinglePhaseFluidAccessors,
+ permeabilityAccessors,
+ mobilePrimarySpeciesFlags,
+ dt,
+ localMatrix,
+ localRhs ),
+ m_temp( thermalSinglePhaseFlowAccessors.get( fields::flow::temperature {} ) ),
+ m_faceTemp( faceManager.getField< fields::flow::faceTemperature >() ),
+ m_enthalpy( thermalReactiveSinglePhaseFluidAccessors.get( fields::singlefluid::enthalpy {} ) ),
+ m_dEnthalpy( thermalReactiveSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy {} ) ),
+ m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ),
+ m_dThermalCond_dT( thermalConductivityAccessors.get( fields::thermalconductivity::dEffectiveConductivity_dT {} ) )
+ {}
+
+
+ /**
+ * @struct StackVariables
+ * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack
+ */
+ struct StackVariables : Base::StackVariables
+ {
+public:
+
+ /**
+ * @brief Constructor for the stack variables
+ * @param[in] size size of the stencil for this connection
+ * @param[in] numElems number of elements for this connection
+ */
+ GEOS_HOST_DEVICE
+ StackVariables( localIndex const size,
+ localIndex numElems ):
+ Base::StackVariables( size,
+ numElems )
+ {}
+
+ using Base::StackVariables::localFlux;
+ using Base::StackVariables::localFluxJacobian;
+ using Base::StackVariables::dofColIndices;
+ using Base::StackVariables::transmissibility;
+
+ /// Energy fluxes and derivatives wrt pressure and temperature
+ real64 energyFlux = 0.0;
+ real64 dEnergyFlux_dP = 0.0;
+ real64 dEnergyFlux_dT = 0.0;
+ };
+
+ /**
+ * @brief Compute the local Dirichlet face flux contributions to the residual and Jacobian
+ * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes
+ */
+ GEOS_HOST_DEVICE
+ void computeFlux( localIndex const iconn,
+ StackVariables & stack ) const
+ {
+ Base::computeFlux( iconn, stack, [&] ( localIndex const er,
+ localIndex const esr,
+ localIndex const ei,
+ localIndex const kf,
+ real64 const & f,
+ real64 const & dF_dP,
+ real64 const & mobility_up,
+ real64 const & dMobility_dP_up )
+ {
+ // Compute the derivatives of the density wrt temperature
+
+ real64 const dDens_dT = 0.5 * m_dDens[er][esr][ei][0][DerivOffset::dT];
+ // Compute the derivatives of the phase potential difference wrt temperature
+
+ real64 const dF_dT = -stack.transmissibility * dDens_dT * ( m_gravCoef[er][esr][ei] - m_faceGravCoef[kf] );
+
+ // Compute the (upwinded) energy flux
+
+ real64 const flux = mobility_up * f;
+ real64 const enthalpy = m_enthalpy[er][esr][ei][0];
+ stack.energyFlux += flux * enthalpy;
+
+ // Compute the derivatives of the (upwinded) energy flux wrt pressure and temperature
+
+ if( f >= 0 ) // the element is upstream
+ {
+ real64 const dFlux_dP = mobility_up * dF_dP + dMobility_dP_up * f;
+ real64 const dFlux_dT = mobility_up * dF_dT + m_dMob[er][esr][ei][DerivOffset::dT] * f;
+
+ stack.dEnergyFlux_dP += dFlux_dP * enthalpy + flux * m_dEnthalpy[er][esr][ei][0][DerivOffset::dP];
+ stack.dEnergyFlux_dT += dFlux_dT * enthalpy + flux * m_dEnthalpy[er][esr][ei][0][DerivOffset::dT];
+ }
+ else
+ {
+ real64 const dFlux_dP = mobility_up * dF_dP;
+ real64 const dFlux_dT = mobility_up * dF_dT;
+
+ stack.dEnergyFlux_dP += dFlux_dP * enthalpy;
+ stack.dEnergyFlux_dT += dFlux_dT * enthalpy;
+ }
+
+ // Contribution of energy conduction through the solid phase
+ real64 thermalTrans = 0.0;
+ real64 dThermalTrans_dThermalCond[3]{};
+ m_stencilWrapper.computeWeights( iconn,
+ m_thermalConductivity,
+ thermalTrans,
+ dThermalTrans_dThermalCond );
+
+ real64 const dThermalTrans_dT = LvArray::tensorOps::AiBi< 3 >( dThermalTrans_dThermalCond, m_dThermalCond_dT[er][esr][ei][0] );
+
+ real64 const deltaT = m_temp[er][esr][ei] - m_faceTemp[kf];
+ stack.energyFlux += thermalTrans * deltaT;
+ stack.dEnergyFlux_dT += thermalTrans + dThermalTrans_dT * deltaT;
+
+ // Add energyFlux and its derivatives to localFlux and localFluxJacobian
+ integer const localRowIndexEnergy = numEqn - numSpecies - 1;
+ stack.localFlux[localRowIndexEnergy] = m_dt * stack.energyFlux;
+
+ stack.localFluxJacobian[localRowIndexEnergy][0] = m_dt * stack.dEnergyFlux_dP;
+ stack.localFluxJacobian[localRowIndexEnergy][numDof-numSpecies-1] = m_dt * stack.dEnergyFlux_dT;
+ } );
+
+ }
+
+ /**
+ * @brief Performs the complete phase for the kernel.
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ */
+ GEOS_HOST_DEVICE
+ void complete( localIndex const iconn,
+ StackVariables & stack ) const
+ {
+ Base::complete( iconn, stack, [&] ( localIndex const localRow )
+ {
+ RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn - numSpecies - 1],
+ stack.localFlux[numEqn - numSpecies - 1] );
+
+ AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >
+ ( localRow + numEqn - numSpecies - 1,
+ stack.dofColIndices,
+ stack.localFluxJacobian[numEqn - numSpecies - 1],
+ numDof );
+ } );
+ }
+
+protected:
+
+ /// Views on temperature
+ ElementViewConst< arrayView1d< real64 const > > const m_temp;
+
+ /// Views on face temperature
+ arrayView1d< real64 const > const m_faceTemp;
+
+ /// Views on enthalpies
+ ElementViewConst< arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > > const m_enthalpy;
+ ElementViewConst< arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > > const m_dEnthalpy;
+
+ /// View on thermal conductivity
+ ElementViewConst< arrayView3d< real64 const > > m_thermalConductivity;
+
+ /// View on derivatives of thermal conductivity w.r.t. temperature
+ ElementViewConst< arrayView3d< real64 const > > m_dThermalCond_dT;
+
+};
+
+/**
+ * @class DirichletFluxComputeKernelFactory
+ */
+class DirichletFluxComputeKernelFactory
+{
+public:
+
+ /**
+ * @brief Create a new kernel and launch
+ * @tparam POLICY the policy used in the RAJA kernel
+ * @param[in] numSpecies the number of primary species
+ * @param[in] mobilePrimarySpeciesFlags the array of flags to indicate mobile primary species
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] dofKey string to get the element degrees of freedom numbers
+ * @param[in] solverName name of the solver (to name accessors)
+ * @param[in] faceManager reference to the face manager
+ * @param[in] elemManager reference to the element region manager
+ * @param[in] stencilWrapper reference to the boundary stencil wrapper
+ * @param[in] reactiveFluid the single phase reactive fluid constitutive model
+ * @param[in] dt time step size
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
+ template< typename POLICY >
+ static void
+ createAndLaunch( integer const numSpecies,
+ arrayView1d< integer const > const mobilePrimarySpeciesFlags,
+ globalIndex const rankOffset,
+ string const & dofKey,
+ string const & solverName,
+ FaceManager const & faceManager,
+ ElementRegionManager const & elemManager,
+ BoundaryStencilWrapper const & stencilWrapper,
+ constitutive::reactivefluid::ReactiveThermalCompressibleSinglePhaseFluid & reactiveFluid,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ constitutiveUpdatePassThru( reactiveFluid, [&]( auto & fluid )
+ {
+ using FluidType = TYPEOFREF( fluid );
+ typename FluidType::KernelWrapper fluidWrapper = fluid.createKernelWrapper();
+
+ singlePhaseReactiveBaseKernels::internal::kernelLaunchSelectorCompSwitch( numSpecies, [&]( auto NS )
+ {
+ integer constexpr NUM_SPECIES = NS();
+ integer constexpr NUM_DOF = 2+NS();
+ integer constexpr NUM_EQN = 2+NS();
+
+ using kernelType = DirichletFluxComputeKernel< NUM_SPECIES, NUM_EQN, NUM_DOF, typename FluidType::KernelWrapper, constitutive::ThermalCompressibleSinglePhaseFluid >;
+
+ ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor =
+ elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey );
+
+ dofNumberAccessor.setName( solverName + "/accessors/" + dofKey );
+
+ typename kernelType::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName );
+ typename kernelType::ReactiveSinglePhaseFlowAccessors reactiveFlowAccessors( elemManager, solverName );
+ typename kernelType::ThermalSinglePhaseFlowAccessors thermalSinglePhaseFlowAccessors( elemManager, solverName );
+ typename kernelType::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName );
+ typename kernelType::ReactiveSinglePhaseFluidAccessors reactiveFluidAccessors( elemManager, solverName );
+ typename kernelType::ThermalReactiveSinglePhaseFluidAccessors thermalFluidAccessors( elemManager, solverName );
+ typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName );
+ typename kernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName );
+
+ kernelType kernel( rankOffset,
+ faceManager,
+ stencilWrapper,
+ fluidWrapper,
+ dofNumberAccessor,
+ singlePhaseFlowAccessors,
+ reactiveFlowAccessors,
+ thermalSinglePhaseFlowAccessors,
+ singlePhaseFluidAccessors,
+ reactiveFluidAccessors,
+ thermalFluidAccessors,
+ permeabilityAccessors,
+ thermalConductivityAccessors,
+ mobilePrimarySpeciesFlags,
+ dt,
+ localMatrix,
+ localRhs );
+
+ kernelType::template launch< POLICY >( stencilWrapper.size(), kernel );
+ } );
+ } );
+ }
+
+};
+
+} // namespace thermalSinglePhaseReactiveFVMKernels
+
+} // namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalFluxComputeKernel.hpp
new file mode 100644
index 00000000000..d436b261628
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/reactive/ThermalFluxComputeKernel.hpp
@@ -0,0 +1,635 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ThermalFluxComputeKernel.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_THERMALFLUXCOMPUTEKERNEL_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_THERMALFLUXCOMPUTEKERNEL_HPP
+
+#include "physicsSolvers/fluidFlow/kernels/singlePhase/reactive/FluxComputeKernel.hpp"
+
+#include "constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp"
+#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp"
+
+namespace geos
+{
+
+namespace thermalSinglePhaseReactiveFVMKernels
+{
+/******************************** FluxComputeKernel ********************************/
+
+/**
+ * @class FluxComputeKernel
+ * @tparam NUM_SPECIES number of fluid primary species
+ * @tparam NUM_EQN number of equations
+ * @tparam NUM_DOF number of degrees of freedom
+ * @tparam STENCILWRAPPER the type of the stencil wrapper
+ * @tparam BASE_FLUID_TYPE the type of the base model for the reactive fluid model
+ * @brief Define the interface for the assembly kernel in charge of flux terms
+ */
+template< integer NUM_SPECIES, integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER, typename BASE_FLUID_TYPE >
+class FluxComputeKernel : public singlePhaseReactiveFVMKernels::FluxComputeKernel< NUM_SPECIES, NUM_EQN, NUM_DOF, STENCILWRAPPER, BASE_FLUID_TYPE >
+{
+public:
+
+ /**
+ * @brief The type for element-based data. Consists entirely of ArrayView's.
+ *
+ * Can be converted from ElementRegionManager::ElementViewConstAccessor
+ * by calling .toView() or .toViewConst() on an accessor instance
+ */
+ template< typename VIEWTYPE >
+ using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >;
+
+ using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase;
+ using DofNumberAccessor = AbstractBase::DofNumberAccessor;
+ using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors;
+ using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors;
+ using PermeabilityAccessors = AbstractBase::PermeabilityAccessors;
+
+ using AbstractBase::m_dt;
+ using AbstractBase::m_rankOffset;
+ using AbstractBase::m_dofNumber;
+ using AbstractBase::m_gravCoef;
+ using AbstractBase::m_mob;
+ using AbstractBase::m_dMob;
+ using AbstractBase::m_dens;
+ using AbstractBase::m_dDens;
+
+ using Base = singlePhaseReactiveFVMKernels::FluxComputeKernel< NUM_SPECIES, NUM_EQN, NUM_DOF, STENCILWRAPPER, BASE_FLUID_TYPE >;
+ using ReactiveSinglePhaseFlowAccessors = typename Base::ReactiveSinglePhaseFlowAccessors;
+ using ReactiveSinglePhaseFluidAccessors = typename Base::ReactiveSinglePhaseFluidAccessors;
+ using DiffusionAccessors = typename Base::DiffusionAccessors;
+ using PorosityAccessors = typename Base::PorosityAccessors;
+ using Base::numSpecies;
+ using Base::numFluxSupportPoints;
+ using Base::numDof;
+ using Base::numEqn;
+ using Base::maxNumElems;
+ using Base::maxNumConns;
+ using Base::maxStencilSize;
+ using Base::m_stencilWrapper;
+ using Base::m_seri;
+ using Base::m_sesri;
+ using Base::m_sei;
+ using Base::m_primarySpeciesMobileAggregateConc;
+ using Base::m_referencePorosity;
+ using Base::m_mobilePrimarySpeciesFlags;
+
+ using ThermalSinglePhaseFlowAccessors =
+ StencilAccessors< fields::flow::temperature >;
+
+ using ThermalReactiveSinglePhaseFluidAccessors =
+ StencilMaterialAccessors< constitutive::reactivefluid::ReactiveSinglePhaseFluid< BASE_FLUID_TYPE >,
+ fields::singlefluid::enthalpy,
+ fields::singlefluid::dEnthalpy >;
+
+ using ThermalConductivityAccessors =
+ StencilMaterialAccessors< constitutive::SinglePhaseThermalConductivityBase,
+ fields::thermalconductivity::effectiveConductivity,
+ fields::thermalconductivity::dEffectiveConductivity_dT >;
+
+
+ /**
+ * @brief Constructor for the kernel interface
+ * @param[in] rankOffset the offset of my MPI rank
+ * @param[in] stencilWrapper reference to the stencil wrapper
+ * @param[in] dofNumberAccessor accessor for the dofs numbers
+ * @param[in] singlePhaseFlowAccessors accessor for wrappers registered by the solver
+ * @param[in] reactiveSinglePhaseFlowAccessors accessor for *reactive* wrappers registered by the solver
+ * @param[in] thermalSinglePhaseFlowAccessors accessor for *thermal* wrappers registered by the solver
+ * @param[in] singlePhaseFluidAccessors accessor for wrappers registered by the single fluid model
+ * @param[in] reactiveSinglePhaseFluidAccessors accessor for *reactive* wrappers registered by the single fluid model
+ * @param[in] thermalReactiveSinglePhaseFluidAccessors accessor for *thermal reactive* wrappers registered by the single fluid model
+ * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model
+ * @param[in] diffusionAccessors accessor for wrappers registered by the diffusion model
+ * @param[in] porosityAccessors accessor for wrappers registered by the porosity model
+ * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model
+ * @param[in] hasDiffusion the flag to turn on diffusion calculation
+ * @param[in] mobilePrimarySpeciesFlags the array of flags to indicate mobile primary species
+ * @param[in] dt time step size
+ * @param[inout] localMatrix the local CRS matrix
+ * @param[inout] localRhs the local right-hand side vector
+ */
+ FluxComputeKernel( globalIndex const rankOffset,
+ STENCILWRAPPER const & stencilWrapper,
+ DofNumberAccessor const & dofNumberAccessor,
+ SinglePhaseFlowAccessors const & singlePhaseFlowAccessors,
+ ReactiveSinglePhaseFlowAccessors const & reactiveSinglePhaseFlowAccessors,
+ ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors,
+ SinglePhaseFluidAccessors const & singlePhaseFluidAccessors,
+ ReactiveSinglePhaseFluidAccessors const & reactiveSinglePhaseFluidAccessors,
+ ThermalReactiveSinglePhaseFluidAccessors const & thermalReactiveSinglePhaseFluidAccessors,
+ PermeabilityAccessors const & permeabilityAccessors,
+ DiffusionAccessors const & diffusionAccessors,
+ PorosityAccessors const & porosityAccessors,
+ ThermalConductivityAccessors const & thermalConductivityAccessors,
+ integer const & hasDiffusion,
+ arrayView1d< integer const > const & mobilePrimarySpeciesFlags,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ : Base( rankOffset,
+ stencilWrapper,
+ dofNumberAccessor,
+ singlePhaseFlowAccessors,
+ reactiveSinglePhaseFlowAccessors,
+ singlePhaseFluidAccessors,
+ reactiveSinglePhaseFluidAccessors,
+ permeabilityAccessors,
+ diffusionAccessors,
+ porosityAccessors,
+ hasDiffusion,
+ mobilePrimarySpeciesFlags,
+ dt,
+ localMatrix,
+ localRhs ),
+ m_temp( thermalSinglePhaseFlowAccessors.get( fields::flow::temperature {} ) ),
+ m_enthalpy( thermalReactiveSinglePhaseFluidAccessors.get( fields::singlefluid::enthalpy {} ) ),
+ m_dEnthalpy( thermalReactiveSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy {} ) ),
+ // m_dPrimarySpeciesMobileAggregateConcentration_dTemp( fluid.dPrimarySpeciesMobileAggregateConcentration_dTemp() ),
+ m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ),
+ m_dThermalCond_dT( thermalConductivityAccessors.get( fields::thermalconductivity::dEffectiveConductivity_dT {} ) )
+ {}
+
+ struct StackVariables : public Base::StackVariables
+ {
+public:
+
+ GEOS_HOST_DEVICE
+ StackVariables( localIndex const size, localIndex numElems )
+ : Base::StackVariables( size, numElems ),
+ energyFlux( 0.0 ),
+ dEnergyFlux_dP( size ),
+ dEnergyFlux_dT( size )
+ {}
+
+ using Base::StackVariables::stencilSize;
+ using Base::StackVariables::numFluxElems;
+ using Base::StackVariables::transmissibility;
+ using Base::StackVariables::dTrans_dPres;
+ using Base::StackVariables::dofColIndices;
+ using Base::StackVariables::localFlux;
+ using Base::StackVariables::localFluxJacobian;
+ using Base::StackVariables::diffusionTransmissibility;
+ using Base::StackVariables::dDiffusionTrans_dT;
+
+
+ // Thermal transmissibility
+ real64 thermalTransmissibility[maxNumConns][2]{};
+
+ /// Derivatives of thermal transmissibility with respect to temperature
+ real64 dThermalTrans_dT[maxNumConns][2]{};
+
+ // Energy fluxes and derivatives
+
+ /// Energy fluxes
+ real64 energyFlux;
+ /// Derivatives of energy fluxes wrt pressure
+ stackArray1d< real64, maxStencilSize > dEnergyFlux_dP;
+ /// Derivatives of energy fluxes wrt temperature
+ stackArray1d< real64, maxStencilSize > dEnergyFlux_dT;
+
+ };
+
+ /**
+ * @brief Compute the local flux contributions to the residual and Jacobian
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ */
+ GEOS_HOST_DEVICE
+ void computeFlux( localIndex const iconn,
+ StackVariables & stack ) const
+ {
+ using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< 1 >;
+ // ***********************************************
+ // First, we call the base computeFlux to compute:
+ // 1) massFlux and speciesFlux and their derivatives (including derivatives wrt temperature),
+ // 2) enthalpy part of energyFlux and its derivatives (including derivatives wrt temperature)
+ //
+ // Computing dFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux,
+ // such as potGrad, fluxVal, and the indices of the upwind cell
+ // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables
+ Base::computeFlux( iconn, stack, [&] ( localIndex const (&k)[2],
+ localIndex const (&seri)[2],
+ localIndex const (&sesri)[2],
+ localIndex const (&sei)[2],
+ localIndex const connectionIndex,
+ real64 const alpha,
+ real64 const mobility,
+ real64 const & potGrad,
+ real64 const & fluxVal,
+ real64 const (&dFlux_dP)[2],
+ real64 const fluidDens_up )
+ {
+ // Step 1: compute the derivatives of the (upwinded) massFlux wrt temperature
+ // --------------------------------------------------------------------------
+ // Step 1.1: compute the derivatives of the mean density at the interface wrt temperature
+ real64 dDensMean_dT[numFluxSupportPoints]{0.0, 0.0};
+
+ real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], stack.transmissibility[connectionIndex][1] };
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ dDensMean_dT[ke] = 0.5 * m_dDens[seri[ke]][sesri[ke]][sei[ke]][0][DerivOffset::dT];
+ }
+
+ // Step 1.2: compute the derivatives of the potential difference wrt temperature
+ real64 dGravHead_dT[numFluxSupportPoints]{0.0, 0.0};
+
+ // compute derivative of gravity potential difference wrt temperature
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ localIndex const er = seri[ke];
+ localIndex const esr = sesri[ke];
+ localIndex const ei = sei[ke];
+
+ real64 const gravD = trans[ke] * m_gravCoef[er][esr][ei];
+
+ for( integer i = 0; i < numFluxSupportPoints; ++i )
+ {
+ dGravHead_dT[i] += dDensMean_dT[i] * gravD;
+ }
+ }
+
+ real64 dFlux_dT[numFluxSupportPoints]{0.0, 0.0};
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ dFlux_dT[ke] -= dGravHead_dT[ke];
+ }
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ dFlux_dT[ke] *= mobility;
+ }
+
+ // compute the derivatives of the mobility wrt temperature
+ // *** upwinding ***
+ real64 dMob_dT[numFluxSupportPoints]{};
+
+ if( alpha <= 0.0 || alpha >= 1.0 )
+ {
+ localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) );
+ dMob_dT[k_up] = m_dMob[seri[k_up]][sesri[k_up]][sei[k_up]][DerivOffset::dT];
+ }
+ else
+ {
+ real64 const mobWeights[numFluxSupportPoints] = { alpha, 1.0 - alpha };
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ dMob_dT[ke] = mobWeights[ke] * m_dMob[seri[ke]][sesri[ke]][sei[ke]][DerivOffset::dT];
+ }
+ }
+
+ // add contribution from upstream cell mobility derivatives
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ dFlux_dT[ke] += dMob_dT[ke] * potGrad;
+ }
+
+ // Step 1.3: populate local jacobian
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ localIndex const localDofIndexTemp = k[ke] * numDof + numDof - numSpecies - 1;
+ stack.localFluxJacobian[k[0]*numEqn][localDofIndexTemp] += m_dt * dFlux_dT[ke];
+ stack.localFluxJacobian[k[1]*numEqn][localDofIndexTemp] -= m_dt * dFlux_dT[ke];
+ }
+
+ // Step 2: compute the derivatives of the speciesFlux wrt temperature
+ // -------------------------------------------------------------------
+ real64 dSpeciesFlux_dT[numFluxSupportPoints][numSpecies]{};
+
+ {
+ // Step 2.1: compute the derivatives of the upstream density wrt temperature
+ // choose upstream cell
+ localIndex const k_up = (potGrad >= 0) ? 0 : 1;
+
+ localIndex const er_up = seri[k_up];
+ localIndex const esr_up = sesri[k_up];
+ localIndex const ei_up = sei[k_up];
+
+ real64 const dDens_dTemp = m_dDens[er_up][esr_up][ei_up][0][DerivOffset::dT];
+
+ // Step 2.2: compute speciesFlux derivative wrt temperature
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ real64 const aggregateConc_i = m_primarySpeciesMobileAggregateConc[er_up][esr_up][ei_up][0][is];
+
+ // real64 const dAggregateConc_i_dTemp = m_dPrimarySpeciesMobileAggregateConcentration_dTemp[er_up][esr_up][ei_up][is];
+ // dSpeciesFlux_dT[k_up][is] += dAggregateConc_i_dTemp * fluxVal / fluidDens_up;
+ dSpeciesFlux_dT[k_up][is] += -aggregateConc_i * fluxVal * dDens_dTemp / (fluidDens_up * fluidDens_up);
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ dSpeciesFlux_dT[ke][is] += aggregateConc_i / fluidDens_up * dFlux_dT[ke];
+ }
+ }
+ }
+
+ // Step 2.3: populate local jacobian
+ for( integer is = 0; is < numSpecies; ++is )
+ {
+ integer const eqIndex0 = k[0] * numEqn + numEqn - numSpecies + is;
+ integer const eqIndex1 = k[1] * numEqn + numEqn - numSpecies + is;
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ localIndex const localDofIndexTemp = k[ke] * numDof + numDof - numSpecies - 1;
+
+ stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dSpeciesFlux_dT[ke][is] * m_mobilePrimarySpeciesFlags[is];
+ stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dSpeciesFlux_dT[ke][is] * m_mobilePrimarySpeciesFlags[is];
+ }
+ }
+
+ // Step 3: compute the enthalpy flux
+ // ----------------------------------
+ real64 enthalpy = 0.0;
+ real64 dEnthalpy_dP[numFluxSupportPoints]{0.0, 0.0};
+ real64 dEnthalpy_dT[numFluxSupportPoints]{0.0, 0.0};
+ // Todo: to add the enthalpy derivatives wrt speciesConc if needed
+ // real64 dEnthalpy_dLogConc[numFluxSupportPoints][numSpecies]{};
+
+ if( alpha <= 0.0 || alpha >= 1.0 )
+ {
+ localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) );
+
+ enthalpy = m_enthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0];
+ dEnthalpy_dP[k_up] = m_dEnthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0][DerivOffset::dP];
+ dEnthalpy_dT[k_up] = m_dEnthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0][DerivOffset::dT];
+ }
+ else
+ {
+ real64 const mobWeights[numFluxSupportPoints] = { alpha, 1.0 - alpha };
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ enthalpy += mobWeights[ke] * m_enthalpy[seri[ke]][sesri[ke]][sei[ke]][0];
+ dEnthalpy_dP[ke] = mobWeights[ke] * m_dEnthalpy[seri[ke]][sesri[ke]][sei[ke]][0][DerivOffset::dP];
+ dEnthalpy_dT[ke] = mobWeights[ke] * m_dEnthalpy[seri[ke]][sesri[ke]][sei[ke]][0][DerivOffset::dT];
+ }
+ }
+
+ stack.energyFlux += fluxVal * enthalpy;
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ stack.dEnergyFlux_dP[ke] += dFlux_dP[ke] * enthalpy;
+ stack.dEnergyFlux_dT[ke] += dFlux_dT[ke] * enthalpy;
+ }
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ stack.dEnergyFlux_dP[ke] += fluxVal * dEnthalpy_dP[ke];
+ stack.dEnergyFlux_dT[ke] += fluxVal * dEnthalpy_dT[ke];
+ }
+
+ } );
+
+ // *****************************************************
+ // Computation of the conduction term in the energy flux
+ // Note that the enthalpy term in the energy was computed above
+ // Note that this term is computed using an explicit treatment of conductivity for now
+
+ // Step 1: compute the thermal transmissibilities at this face
+ // We follow how the thermal compositional multi-phase solver does to update the thermal transmissibility
+ m_stencilWrapper.computeWeights( iconn,
+ m_thermalConductivity,
+ m_dThermalCond_dT,
+ stack.thermalTransmissibility,
+ stack.dThermalTrans_dT );
+
+ localIndex k[numFluxSupportPoints];
+ localIndex connectionIndex = 0;
+
+ for( k[0] = 0; k[0] < stack.numFluxElems; ++k[0] )
+ {
+ for( k[1] = k[0] + 1; k[1] < stack.numFluxElems; ++k[1] )
+ {
+ real64 const thermalTrans[numFluxSupportPoints] = { stack.thermalTransmissibility[connectionIndex][0], stack.thermalTransmissibility[connectionIndex][1] };
+ real64 const dThermalTrans_dT[numFluxSupportPoints] = { stack.dThermalTrans_dT[connectionIndex][0], stack.dThermalTrans_dT[connectionIndex][1] };
+
+ localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )};
+ localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )};
+ localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )};
+
+ // Step 2: compute temperature difference at the interface
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ localIndex const er = seri[ke];
+ localIndex const esr = sesri[ke];
+ localIndex const ei = sei[ke];
+
+ stack.energyFlux += thermalTrans[ke] * m_temp[er][esr][ei];
+ stack.dEnergyFlux_dT[ke] += thermalTrans[ke] + dThermalTrans_dT[ke] * m_temp[er][esr][ei];
+ }
+
+ integer const eqIndex0 = k[0] * numEqn + numEqn - numSpecies - 1;
+ integer const eqIndex1 = k[1] * numEqn + numEqn - numSpecies - 1;
+
+ // add energyFlux and its derivatives to localFlux and localFluxJacobian
+ stack.localFlux[eqIndex0] += m_dt * stack.energyFlux;
+ stack.localFlux[eqIndex1] -= m_dt * stack.energyFlux;
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ integer const localDofIndexPres = k[ke] * numDof;
+ stack.localFluxJacobian[eqIndex0][localDofIndexPres] = m_dt * stack.dEnergyFlux_dP[ke];
+ stack.localFluxJacobian[eqIndex1][localDofIndexPres] = -m_dt * stack.dEnergyFlux_dP[ke];
+ integer const localDofIndexTemp = localDofIndexPres + numDof - numSpecies - 1;
+ stack.localFluxJacobian[eqIndex0][localDofIndexTemp] = m_dt * stack.dEnergyFlux_dT[ke];
+ stack.localFluxJacobian[eqIndex1][localDofIndexTemp] = -m_dt * stack.dEnergyFlux_dT[ke];
+ }
+
+ connectionIndex++;
+ }
+ }
+ }
+
+ /**
+ * @brief Compute the local flux contributions to the residual and Jacobian
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ */
+ GEOS_HOST_DEVICE
+ void computeDiffusion( localIndex const iconn,
+ StackVariables & stack ) const
+ {
+ Base::computeDiffusion( iconn, stack, [&] ( integer const is,
+ localIndex const (&k)[2],
+ localIndex const (&seri)[2],
+ localIndex const (&sesri)[2],
+ localIndex const (&sei)[2],
+ localIndex const connectionIndex,
+ localIndex const k_up )
+ {
+ real64 dDiffusionFlux_dT[numFluxSupportPoints]{};
+ real64 dSpeciesGrad_dT[numFluxSupportPoints]{};
+
+ // Calculate diffusion derivative wrt temperature
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ localIndex const er = seri[ke];
+ localIndex const esr = sesri[ke];
+ localIndex const ei = sei[ke];
+
+ // dSpeciesGrad_dT[ke] += stack.diffusionTransmissibility[connectionIndex][ke]
+ // * m_dPrimarySpeciesMobileAggregateConcentration_dTemp[er][esr][ei][is];
+
+ dSpeciesGrad_dT[ke] += stack.dDiffusionTrans_dT[connectionIndex][ke] * m_primarySpeciesMobileAggregateConc[er][esr][ei][0][is];
+ }
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ke++ )
+ {
+ localIndex const er_up = seri[k_up];
+ localIndex const esr_up = sesri[k_up];
+ localIndex const ei_up = sei[k_up];
+
+ dDiffusionFlux_dT[ke] += m_referencePorosity[er_up][esr_up][ei_up] * dSpeciesGrad_dT[ke];
+ }
+
+ // populate local Jacobian
+ integer const eqIndex0 = k[0] * numEqn + numEqn - numSpecies + is;
+ integer const eqIndex1 = k[1] * numEqn + numEqn - numSpecies + is;
+
+ for( integer ke = 0; ke < numFluxSupportPoints; ++ke )
+ {
+ localIndex const localDofIndexTemp = k[ke] * numDof + numDof - numSpecies - 1;
+ stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dDiffusionFlux_dT[ke] * m_mobilePrimarySpeciesFlags[is];
+ stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dDiffusionFlux_dT[ke] * m_mobilePrimarySpeciesFlags[is];
+ }
+ } );
+ }
+
+ /**
+ * @brief Performs the complete phase for the kernel.
+ * @param[in] iconn the connection index
+ * @param[inout] stack the stack variables
+ */
+ GEOS_HOST_DEVICE
+ void complete( localIndex const iconn,
+ StackVariables & stack ) const
+ {
+ // Call Case::complete to assemble the mass balance equations
+ // In the lambda, add contribution to residual and jacobian into the energy balance equation
+ Base::complete( iconn, stack, [&] ( integer const i,
+ localIndex const localRow )
+ {
+ // The no. of fluxes is equal to the no. of equations in m_localRhs and m_localMatrix
+ // Different from the one in compositional multi-phase flow, which has a volume balance eqn.
+ RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn - numSpecies - 1], stack.localFlux[i * numEqn + numEqn - numSpecies - 1] );
+
+ AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( localRow + numEqn - numSpecies - 1,
+ stack.dofColIndices.data(),
+ stack.localFluxJacobian[i * numEqn + numEqn - numSpecies - 1].dataIfContiguous(),
+ stack.stencilSize * numDof );
+
+ } );
+ }
+
+protected:
+
+ /// Views on temperature
+ ElementViewConst< arrayView1d< real64 const > > const m_temp;
+
+ /// Views on enthalpies
+ ElementViewConst< arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > > const m_enthalpy;
+ ElementViewConst< arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > > const m_dEnthalpy;
+
+ // /// Views on the derivative of primary species aggregate concentration wrt temperature
+ // ElementViewConst< arrayView2d< real64 const, compflow::USD_COMP > > const m_dPrimarySpeciesAggregateConc_dTemp;
+
+ /// View on thermal conductivity
+ ElementViewConst< arrayView3d< real64 const > > m_thermalConductivity;
+
+ /// View on derivatives of thermal conductivity w.r.t. temperature
+ ElementViewConst< arrayView3d< real64 const > > m_dThermalCond_dT;
+
+};
+
+/**
+ * @class 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] numSpecies the number of primary species
+ * @param[in] hasDiffusion the flag of adding diffusion term
+ * @param[in] mobilePrimarySpeciesFlags the array of flags to indicate mobile primary species
+ * @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 numSpecies,
+ integer const hasDiffusion,
+ arrayView1d< integer const > const mobilePrimarySpeciesFlags,
+ globalIndex const rankOffset,
+ string const & dofKey,
+ string const & solverName,
+ ElementRegionManager const & elemManager,
+ STENCILWRAPPER const & stencilWrapper,
+ real64 const & dt,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ singlePhaseReactiveBaseKernels::internal::kernelLaunchSelectorCompSwitch( numSpecies, [&]( auto NS )
+ {
+ integer constexpr NUM_SPECIES = NS();
+ integer constexpr NUM_DOF = 2+NS();
+ integer constexpr NUM_EQN = 2+NS();
+
+ ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor =
+ elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey );
+ dofNumberAccessor.setName( solverName + "/accessors/" + dofKey );
+
+ using KernelType = FluxComputeKernel< NUM_SPECIES, NUM_EQN, NUM_DOF, STENCILWRAPPER, constitutive::ThermalCompressibleSinglePhaseFluid >;
+ typename KernelType::SinglePhaseFlowAccessors flowAccessors( elemManager, solverName );
+ typename KernelType::ReactiveSinglePhaseFlowAccessors reactiveFlowAccessors( elemManager, solverName );
+ typename KernelType::ThermalSinglePhaseFlowAccessors thermalFlowAccessors( elemManager, solverName );
+ typename KernelType::SinglePhaseFluidAccessors fluidAccessors( elemManager, solverName );
+ typename KernelType::ReactiveSinglePhaseFluidAccessors reactiveFluidAccessors( elemManager, solverName );
+ typename KernelType::ThermalReactiveSinglePhaseFluidAccessors thermalFluidAccessors( elemManager, solverName );
+ typename KernelType::PermeabilityAccessors permAccessors( elemManager, solverName );
+ typename KernelType::DiffusionAccessors diffusionAccessors( elemManager, solverName );
+ typename KernelType::PorosityAccessors porosityAccessors( elemManager, solverName );
+ typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName );
+
+ KernelType kernel( rankOffset, stencilWrapper, dofNumberAccessor,
+ flowAccessors, reactiveFlowAccessors, thermalFlowAccessors, fluidAccessors, reactiveFluidAccessors, thermalFluidAccessors,
+ permAccessors, diffusionAccessors, porosityAccessors, thermalConductivityAccessors,
+ hasDiffusion, mobilePrimarySpeciesFlags, dt, localMatrix, localRhs );
+ KernelType::template launch< POLICY >( stencilWrapper.size(), kernel );
+ } );
+ }
+};
+
+} // namespace thermalSinglePhaseReactiveFVMKernels
+
+} // namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEREACTIVE_THERMALFLUXCOMPUTEKERNEL_HPP
diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledSolver.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledSolver.hpp
index 333220bff67..300088cf592 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/CoupledSolver.hpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledSolver.hpp
@@ -511,7 +511,7 @@ class CoupledSolver : public PhysicsSolverBase
solver->saveSequentialIterationState( domain );
}
- mapSolutionBetweenSolvers( domain, idx() );
+ mapSolutionBetweenSolvers( stepDt, domain, idx() );
if( solverDt < stepDt ) // subsolver had to cut the time step
{
@@ -588,13 +588,15 @@ class CoupledSolver : public PhysicsSolverBase
/**
* @brief Maps the solution obtained from one solver to the fields used by the other solver(s)
*
+ * @param dt timestep size
* @param domain the domain partition
* @param solverType the index of the solver withing this coupled solver.
*/
- virtual void mapSolutionBetweenSolvers( DomainPartition & domain,
+ virtual void mapSolutionBetweenSolvers( real64 const & dt,
+ DomainPartition & domain,
integer const solverType )
{
- GEOS_UNUSED_VAR( domain, solverType );
+ GEOS_UNUSED_VAR( dt, domain, solverType );
}
virtual bool checkSequentialConvergence( integer const cycleNumber,
diff --git a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.cpp b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.cpp
index 751dd7dea77..033929e4fd3 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.cpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.cpp
@@ -50,9 +50,10 @@ void PhaseFieldFractureSolver::postInputInitialization()
getNonlinearSolverParameters().m_couplingType = NonlinearSolverParameters::CouplingType::Sequential;
}
-void PhaseFieldFractureSolver::mapSolutionBetweenSolvers( DomainPartition & domain, integer const solverType )
+void PhaseFieldFractureSolver::mapSolutionBetweenSolvers( real64 const & dt, DomainPartition & domain, integer const solverType )
{
-
+ GEOS_UNUSED_VAR( dt );
+
GEOS_MARK_FUNCTION;
if( solverType == static_cast< integer >( SolverType::Damage ) )
{
diff --git a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.hpp b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.hpp
index a1aae598694..af63526d7ca 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.hpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldFractureSolver.hpp
@@ -86,7 +86,7 @@ class PhaseFieldFractureSolver : public CoupledSolver< SolidMechanicsLagrangianF
return std::get< toUnderlying( SolverType::Damage ) >( m_solvers );
}
- virtual void mapSolutionBetweenSolvers( DomainPartition & Domain, integer const idx ) override final;
+ virtual void mapSolutionBetweenSolvers( real64 const & dt, DomainPartition & Domain, integer const idx ) override final;
protected:
diff --git a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldPoromechanicsSolver.cpp b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldPoromechanicsSolver.cpp
index 06bb5259f06..e18a7343cf7 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldPoromechanicsSolver.cpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldPoromechanicsSolver.cpp
@@ -57,8 +57,10 @@ PhaseFieldPoromechanicsSolver::~PhaseFieldPoromechanicsSolver()
// TODO Auto-generated destructor stub
}
-void PhaseFieldPoromechanicsSolver::mapSolutionBetweenSolvers( DomainPartition & domain, integer const solverType )
+void PhaseFieldPoromechanicsSolver::mapSolutionBetweenSolvers( real64 const & dt, DomainPartition & domain, integer const solverType )
{
+ GEOS_UNUSED_VAR( dt );
+
if( solverType == static_cast< integer >( SolverType::Damage ) )
{
GEOS_MARK_FUNCTION;
diff --git a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldPoromechanicsSolver.hpp b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldPoromechanicsSolver.hpp
index 359f428a3c3..76eac71b4c3 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldPoromechanicsSolver.hpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/PhaseFieldPoromechanicsSolver.hpp
@@ -87,7 +87,7 @@ class PhaseFieldPoromechanicsSolver : public CoupledSolver< SinglePhasePoromecha
return std::get< toUnderlying( SolverType::Damage ) >( m_solvers );
}
- virtual void mapSolutionBetweenSolvers( DomainPartition & Domain, integer const idx ) override final;
+ virtual void mapSolutionBetweenSolvers( real64 const & dt, DomainPartition & Domain, integer const idx ) override final;
void mapDamageAndGradientToQuadrature( DomainPartition & domain );
diff --git a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsConformingFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsConformingFractures.hpp
index 2366f915fd4..5a25e5241ec 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsConformingFractures.hpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsConformingFractures.hpp
@@ -564,7 +564,7 @@ class PoromechanicsConformingFractures : public POROMECHANICS_BASE< FLOW_SOLVER,
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs ) = 0;
- virtual void mapSolutionBetweenSolvers( DomainPartition & domain, integer const solverType ) override
+ virtual void mapSolutionBetweenSolvers( real64 const & dt, DomainPartition & domain, integer const solverType ) override
{
GEOS_MARK_FUNCTION;
@@ -581,7 +581,7 @@ class PoromechanicsConformingFractures : public POROMECHANICS_BASE< FLOW_SOLVER,
this->flowSolver()->updateStencilWeights( domain );
}
- Base::mapSolutionBetweenSolvers( domain, solverType );
+ Base::mapSolutionBetweenSolvers( dt, domain, solverType );
}
void updateHydraulicApertureAndFracturePermeability( DomainPartition & domain )
diff --git a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsSolver.hpp b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsSolver.hpp
index f553759e327..ffabe0a92ad 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsSolver.hpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/PoromechanicsSolver.hpp
@@ -127,6 +127,12 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER
EnumStrings< SolidMechanicsLagrangianFEM::TimeIntegrationOption >::toString( SolidMechanicsLagrangianFEM::TimeIntegrationOption::QuasiStatic ) ),
InputError );
+ GEOS_THROW_IF( this->flowSolver()->getCatalogName() == "SinglePhaseReactiveTransport" &&
+ this->getNonlinearSolverParameters().m_couplingType != NonlinearSolverParameters::CouplingType::Sequential,
+ GEOS_FMT( "{} {}: The coupling type must be Sequential since it is coupled with {}",
+ this->getCatalogName(), this->getName(), this->flowSolver()->getCatalogName() ),
+ InputError );
+
setMGRStrategy();
}
@@ -186,10 +192,18 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER
if( this->getNonlinearSolverParameters().m_couplingType == NonlinearSolverParameters::CouplingType::Sequential )
{
- // to let the solid mechanics solver that there is a pressure and temperature RHS in the mechanics solve
- solidMechanicsSolver()->enableFixedStressPoromechanicsUpdate();
- // to let the flow solver that saving pressure_k and temperature_k is necessary (for the fixed-stress porosity terms)
- flowSolver()->enableFixedStressPoromechanicsUpdate();
+ if( flowSolver()->getCatalogName() == "SinglePhaseReactiveTransport" )
+ {
+ // to let the solid mechanics solver to account for anelastic strain due to chemistry
+ solidMechanicsSolver()->enableExplicitChemomechanicsUpdate();
+ }
+ else
+ {
+ // to let the solid mechanics solver that there is a pressure and temperature RHS in the mechanics solve
+ solidMechanicsSolver()->enableFixedStressPoromechanicsUpdate();
+ // to let the flow solver that saving pressure_k and temperature_k is necessary (for the fixed-stress porosity terms)
+ flowSolver()->enableFixedStressPoromechanicsUpdate();
+ }
}
if( m_stabilizationType == stabilization::StabilizationType::Global || m_stabilizationType == stabilization::StabilizationType::Local )
@@ -649,8 +663,10 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER
}
}
- virtual void mapSolutionBetweenSolvers( DomainPartition & domain, integer const solverType ) override
+ virtual void mapSolutionBetweenSolvers( real64 const & dt, DomainPartition & domain, integer const solverType ) override
{
+ GEOS_UNUSED_VAR( dt );
+
GEOS_MARK_FUNCTION;
/// After the flow solver
@@ -663,8 +679,11 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER
if( solverType == static_cast< integer >( SolverType::SolidMechanics )
&& !m_performStressInitialization ) // do not update during poromechanics initialization
{
- // compute the average of the mean total stress increment over quadrature points
- averageMeanTotalStressIncrement( domain );
+ if( flowSolver()->getCatalogName() != "SinglePhaseReactiveTransport" ) // For now, Biot Poromechanics is not considered for ChemoMechanics
+ {
+ // compute the average of the mean total stress increment over quadrature points
+ averageMeanTotalStressIncrement( domain );
+ }
this->template forDiscretizationOnMeshTargets<>( domain.getMeshBodies(), [&]( string const &,
MeshLevel & mesh,
@@ -687,7 +706,10 @@ class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER
if( solverType == static_cast< integer >( SolverType::SolidMechanics ) &&
this->getNonlinearSolverParameters().m_nonlinearAccelerationType== NonlinearSolverParameters::NonlinearAccelerationType::Aitken )
{
- recordAverageMeanTotalStressIncrement( domain, m_s2_tilde );
+ if( flowSolver()->getCatalogName() != "SinglePhaseReactiveTransport" ) // For now, Biot Poromechanics is not considered for ChemoMechanics
+ {
+ recordAverageMeanTotalStressIncrement( domain, m_s2_tilde );
+ }
}
}
diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp
index 7a3fdc6386a..c8ecaadc617 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp
@@ -179,6 +179,30 @@ void SinglePhasePoromechanics< SinglePhaseReservoirAndWells<>, SolidMechanicsLag
flowSolver()->assembleCouplingTerms( time_n, dt, domain, dofManager, localMatrix, localRhs );
}
+template<>
+void SinglePhasePoromechanics< SinglePhaseReactiveTransport, SolidMechanicsLagrangianFEM >::mapSolutionBetweenSolvers( real64 const & dt,
+ DomainPartition & domain,
+ integer const solverType )
+{
+ GEOS_MARK_FUNCTION;
+
+ Base::mapSolutionBetweenSolvers( dt, domain, solverType );
+
+ if( solverType == static_cast< integer >( SolverType::Flow ) )
+ {
+ this->template forDiscretizationOnMeshTargets<>( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions( regionNames, [&]( localIndex const,
+ ElementSubRegionBase & subRegion )
+ {
+ flowSolver()->updateKineticReactionMolarIncrements( dt, subRegion );
+ } );
+ } );
+ }
+}
+
template< typename FLOW_SOLVER, typename MECHANICS_SOLVER >
void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::assembleElementBasedTerms( real64 const time_n,
real64 const dt,
@@ -347,9 +371,12 @@ template class SinglePhasePoromechanics< SinglePhaseBase, SolidMechanicsEmbedded
template class SinglePhasePoromechanics< SinglePhaseReservoirAndWells<> >;
template class SinglePhasePoromechanics< SinglePhaseReservoirAndWells<>, SolidMechanicsLagrangeContact >;
//template class SinglePhasePoromechanics< SinglePhaseReservoirAndWells<>, SolidMechanicsEmbeddedFractures >;
+template class SinglePhasePoromechanics< SinglePhaseReactiveTransport >;
namespace
{
+typedef SinglePhasePoromechanics< SinglePhaseReactiveTransport > SinglePhaseChemomechanics;
+REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseChemomechanics, string const &, Group * const )
typedef SinglePhasePoromechanics< SinglePhaseReservoirAndWells<> > SinglePhaseReservoirPoromechanics;
REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseReservoirPoromechanics, string const &, Group * const )
typedef SinglePhasePoromechanics<> SinglePhasePoromechanics;
diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp
index 0c564bf3d23..e9d0cc9d7ff 100644
--- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp
+++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp
@@ -22,6 +22,7 @@
#include "physicsSolvers/multiphysics/PoromechanicsSolver.hpp"
#include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseReactiveTransport.hpp"
#include "physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.hpp"
namespace geos
@@ -97,6 +98,11 @@ class SinglePhasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHAN
arrayView1d< real64 > const & localRhs ) override
{ Base::assembleSystem( time, dt, domain, dofManager, localMatrix, localRhs ); }
+ virtual void mapSolutionBetweenSolvers( real64 const & dt,
+ DomainPartition & domain,
+ integer const solverType ) override
+ { Base::mapSolutionBetweenSolvers( dt, domain, solverType ); }
+
virtual void assembleElementBasedTerms( real64 const time_n,
real64 const dt,
DomainPartition & domain,
diff --git a/src/coreComponents/physicsSolvers/solidMechanics/CMakeLists.txt b/src/coreComponents/physicsSolvers/solidMechanics/CMakeLists.txt
index ced15c47ba5..c399776c304 100644
--- a/src/coreComponents/physicsSolvers/solidMechanics/CMakeLists.txt
+++ b/src/coreComponents/physicsSolvers/solidMechanics/CMakeLists.txt
@@ -25,6 +25,8 @@ set( solidMechanicsSolvers_headers
kernels/SolidMechanicsLagrangianFEMKernels.hpp
SolidMechanicsMPM.hpp
MPMSolverFields.hpp
+ kernels/ExplicitChemoMechanics.hpp
+ kernels/ExplicitChemoMechanics_impl.hpp
kernels/ExplicitFiniteStrain.hpp
kernels/ExplicitFiniteStrain_impl.hpp
kernels/ExplicitMPM.hpp
@@ -82,7 +84,8 @@ set( kernelTemplateFileList "" )
list( APPEND kernelTemplateFileList
kernels/SolidMechanicsKernels.cpp.template
- kernels/SolidMechanicsFixedStressThermoPoromechanicsKernels.cpp.template )
+ kernels/SolidMechanicsFixedStressThermoPoromechanicsKernels.cpp.template
+ kernels/SolidMechanicsExplicitChemoMechanicsKernels.cpp.template )
foreach( kernelTemplateFile ${kernelTemplateFileList} )
diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.cpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.cpp
index f3dd742fa6d..d1c5bfce738 100644
--- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.cpp
+++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.cpp
@@ -25,6 +25,7 @@
#include "kernels/ExplicitSmallStrain.hpp"
#include "kernels/ExplicitFiniteStrain.hpp"
#include "kernels/FixedStressThermoPoromechanics.hpp"
+#include "kernels/ExplicitChemoMechanics.hpp"
#include "common/GEOS_RAJA_Interface.hpp"
#include "constitutive/ConstitutiveManager.hpp"
@@ -48,6 +49,7 @@
#include "physicsSolvers/LogLevelsInfo.hpp"
#include "physicsSolvers/solidMechanics/kernels/SolidMechanicsKernelsDispatchTypeList.hpp"
#include "physicsSolvers/solidMechanics/kernels/SolidMechanicsFixedStressThermoPoromechanicsKernelsDispatchTypeList.hpp"
+#include "physicsSolvers/solidMechanics/kernels/SolidMechanicsExplicitChemoMechanicsKernelsDispatchTypeList.hpp"
#include "physicsSolvers/fluidFlow/FlowSolverBase.hpp"
namespace geos
@@ -69,7 +71,8 @@ SolidMechanicsLagrangianFEM::SolidMechanicsLagrangianFEM( const string & name,
m_maxNumResolves( 10 ),
m_strainTheory( 0 ),
m_isFixedStressPoromechanicsUpdate( false ),
- m_performStressInitialization( false )
+ m_performStressInitialization( false ),
+ m_isExplicitChemomechanicsUpdate( false )
{
registerWrapper( viewKeyStruct::newmarkGammaString(), &m_newmarkGamma ).
@@ -1132,6 +1135,22 @@ void SolidMechanicsLagrangianFEM::assembleSystem( real64 const GEOS_UNUSED_PARAM
m_maxForce = LvArray::math::max( mechanicsMaxForce, poromechanicsMaxForce );
}
+ else if( m_isExplicitChemomechanicsUpdate )
+ {
+
+ // first pass for coupled poromechanics regions
+ real64 const chemomechanicsMaxForce= assemblyLaunch< SolidMechanicsExplicitChemoMechanicsKernelsDispatchTypeList,
+ solidMechanicsLagrangianFEMKernels::ExplicitChemoMechanicsFactory >( mesh,
+ dofManager,
+ regionNames,
+ FlowSolverBase::viewKeyStruct::solidNamesString(),
+ localMatrix,
+ localRhs,
+ dt );
+
+
+ m_maxForce = chemomechanicsMaxForce;
+ }
else
{
if( m_timeIntegrationOption == TimeIntegrationOption::QuasiStatic )
@@ -1508,6 +1527,11 @@ void SolidMechanicsLagrangianFEM::enableFixedStressPoromechanicsUpdate()
m_isFixedStressPoromechanicsUpdate = true;
}
+void SolidMechanicsLagrangianFEM::enableExplicitChemomechanicsUpdate()
+{
+ m_isExplicitChemomechanicsUpdate = true;
+}
+
void SolidMechanicsLagrangianFEM::saveSequentialIterationState( DomainPartition & GEOS_UNUSED_PARAM( domain ) )
{
// nothing to save
diff --git a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp
index de4c7630f42..3f1d0b777fe 100644
--- a/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp
+++ b/src/coreComponents/physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp
@@ -226,6 +226,8 @@ class SolidMechanicsLagrangianFEM : public PhysicsSolverBase
void enableFixedStressPoromechanicsUpdate();
+ void enableExplicitChemomechanicsUpdate();
+
virtual void saveSequentialIterationState( DomainPartition & domain ) override;
struct viewKeyStruct : PhysicsSolverBase::viewKeyStruct
@@ -307,6 +309,9 @@ class SolidMechanicsLagrangianFEM : public PhysicsSolverBase
/// Flag to indicate that the solver is going to perform stress initialization
bool m_performStressInitialization;
+ /// Flag to indicate that the solver is running with explicit chemomechancis update
+ bool m_isExplicitChemomechanicsUpdate;
+
/// Rigid body modes; TODO remove mutable hack
mutable array1d< ParallelVector > m_rigidBodyModes;
diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernelSpecs.json b/src/coreComponents/physicsSolvers/solidMechanics/kernelSpecs.json
index ca527443f5a..84824c78ec5 100644
--- a/src/coreComponents/physicsSolvers/solidMechanics/kernelSpecs.json
+++ b/src/coreComponents/physicsSolvers/solidMechanics/kernelSpecs.json
@@ -29,6 +29,7 @@
"constants": [
[ "ExplicitSmallStrainPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ],
[ "ExplicitFiniteStrainPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ],
+ [ "ExplicitChemoMechanicsPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ],
[ "FixedStressThermoPoromechanicsPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ],
[ "ImplicitSmallStrainNewmarkPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ],
[ "ImplicitSmallStrainQuasiStaticPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ]
@@ -144,5 +145,37 @@
]
},
"explicit": []
+ },
+
+ "SolidMechanicsExplicitChemoMechanicsKernels": {
+ "vars": [
+ "SUBREGION_TYPE",
+ "CONSTITUTIVE_TYPE",
+ "FE_TYPE"
+ ],
+ "constants": [
+ [ "ExplicitSmallStrainPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ],
+ [ "ExplicitFiniteStrainPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ],
+ [ "ExplicitChemoMechanicsPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ],
+ [ "FixedStressThermoPoromechanicsPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ],
+ [ "ImplicitSmallStrainNewmarkPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ],
+ [ "ImplicitSmallStrainQuasiStaticPolicy", "geos::parallelDevicePolicy< GEOS_BLOCK_SIZE >" ]
+ ],
+ "combinations": {
+ "SUBREGION_TYPE": [
+ "CellElementSubRegion"
+ ],
+ "CONSTITUTIVE_TYPE": [
+ "PorousReactiveSolid",
+ "PorousReactiveSolid"
+ ],
+ "FE_TYPE": [
+ "H1_Hexahedron_Lagrange1_GaussLegendre2",
+ "H1_Wedge_Lagrange1_Gauss6",
+ "H1_Tetrahedron_Lagrange1_Gauss1",
+ "H1_Pyramid_Lagrange1_Gauss5"
+ ]
+ },
+ "explicit": []
}
}
diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitChemoMechanics.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitChemoMechanics.hpp
new file mode 100644
index 00000000000..c0321447f26
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitChemoMechanics.hpp
@@ -0,0 +1,239 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ExplicitChemoMechanics.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_KERNELS_EXPLICITCHEMOMECHANICS_HPP_
+#define GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_KERNELS_EXPLICITCHEMOMECHANICS_HPP_
+
+#include "finiteElement/kernelInterface/ImplicitKernelBase.hpp"
+
+namespace geos
+{
+
+namespace solidMechanicsLagrangianFEMKernels
+{
+
+/**
+ * @brief Implements kernels for solving the solid part of the chemomechanics problem.
+ * @copydoc geos::finiteElement::ImplicitKernelBase
+ * @tparam NUM_NODES_PER_ELEM The number of nodes per element for the
+ * @p SUBREGION_TYPE.
+ * @tparam UNUSED An unused parameter since we are assuming that the test and
+ * trial space have the same number of support points.
+ *
+ * ### ExplicitChemoMechanics Description
+ * Implements the KernelBase interface functions required for using the
+ * effective stress for the integration of the stress divergence. This is
+ * templated on one of the "finite element kernel application" functions
+ * such as geos::finiteElement::RegionBasedKernelApplication.
+ */
+template< typename SUBREGION_TYPE,
+ typename CONSTITUTIVE_TYPE,
+ typename FE_TYPE >
+class ExplicitChemoMechanics :
+ public finiteElement::ImplicitKernelBase< SUBREGION_TYPE,
+ CONSTITUTIVE_TYPE,
+ FE_TYPE,
+ 3,
+ 3 >
+{
+public:
+ /// Alias for the base class;
+ using Base = finiteElement::ImplicitKernelBase< SUBREGION_TYPE,
+ CONSTITUTIVE_TYPE,
+ FE_TYPE,
+ 3,
+ 3 >;
+
+ /// Maximum number of nodes per element, which is equal to the maxNumTestSupportPointPerElem and
+ /// maxNumTrialSupportPointPerElem by definition. When the FE_TYPE is not a Virtual Element, this
+ /// will be the actual number of nodes per element.
+ static constexpr int numNodesPerElem = Base::maxNumTestSupportPointsPerElem;
+ using Base::numDofPerTestSupportPoint;
+ using Base::numDofPerTrialSupportPoint;
+ using Base::m_dofNumber;
+ using Base::m_dofRankOffset;
+ using Base::m_matrix;
+ using Base::m_rhs;
+ using Base::m_elemsToNodes;
+ using Base::m_constitutiveUpdate;
+ using Base::m_finiteElementSpace;
+ using Base::m_meshData;
+ using Base::m_dt;
+
+ /**
+ * @brief Constructor
+ * @copydoc geos::finiteElement::ImplicitKernelBase::ImplicitKernelBase
+ * @param inputGravityVector The gravity vector.
+ */
+ ExplicitChemoMechanics( NodeManager const & nodeManager,
+ EdgeManager const & edgeManager,
+ FaceManager const & faceManager,
+ localIndex const targetRegionIndex,
+ SUBREGION_TYPE const & elementSubRegion,
+ FE_TYPE const & finiteElementSpace,
+ CONSTITUTIVE_TYPE & inputConstitutiveType,
+ arrayView1d< globalIndex const > const inputDofNumber,
+ globalIndex const rankOffset,
+ CRSMatrixView< real64, globalIndex const > const inputMatrix,
+ arrayView1d< real64 > const inputRhs,
+ real64 const inputDt,
+ real64 const (&inputGravityVector)[3] );
+
+ //*****************************************************************************
+ /**
+ * @class StackVariables
+ * @copydoc geos::finiteElement::ImplicitKernelBase::StackVariables
+ *
+ * Adds a stack array for the displacement, incremental displacement, and the
+ * constitutive stiffness.
+ */
+ struct StackVariables : public Base::StackVariables
+ {
+public:
+
+ /// Constructor.
+ GEOS_HOST_DEVICE
+ StackVariables():
+ Base::StackVariables(),
+ xLocal(),
+ u_local(),
+ uhat_local(),
+ constitutiveStiffness()
+ {}
+
+#if !defined(CALC_FEM_SHAPE_IN_KERNEL)
+ /// Dummy
+ int xLocal;
+#else
+ /// C-array stack storage for element local the nodal positions.
+ real64 xLocal[ numNodesPerElem ][ 3 ];
+#endif
+
+ /// Stack storage for the element local nodal displacement
+ real64 u_local[numNodesPerElem][numDofPerTrialSupportPoint];
+
+ /// Stack storage for the element local nodal incremental displacement
+ real64 uhat_local[numNodesPerElem][numDofPerTrialSupportPoint];
+
+ /// Stack storage for the constitutive stiffness at a quadrature point.
+ real64 constitutiveStiffness[ 6 ][ 6 ];
+ };
+ //*****************************************************************************
+
+ /**
+ * @brief Copy global values from primary field to a local stack array.
+ * @copydoc ::geos::finiteElement::ImplicitKernelBase::setup
+ *
+ * For the ExplicitChemoMechanics implementation, global values from the displacement,
+ * incremental displacement, and degree of freedom numbers are placed into
+ * element local stack storage.
+ */
+ GEOS_HOST_DEVICE
+ void setup( localIndex const k,
+ StackVariables & stack ) const;
+
+ /**
+ * @copydoc geos::finiteElement::KernelBase::quadraturePointKernel
+ * For solid mechanics kernels, the strain increment is calculated, and the
+ * constitutive update is called. In addition, the constitutive stiffness
+ * stack variable is filled by the constitutive model.
+ */
+ GEOS_HOST_DEVICE
+ void quadraturePointKernel( localIndex const k,
+ localIndex const q,
+ StackVariables & stack ) const;
+
+ /**
+ * @copydoc geos::finiteElement::ImplicitKernelBase::complete
+ */
+ GEOS_HOST_DEVICE
+ GEOS_FORCE_INLINE
+ real64 complete( localIndex const k,
+ StackVariables & stack ) const;
+
+ /**
+ * @copydoc geos::finiteElement::KernelBase::kernelLaunch
+ */
+ template< typename POLICY,
+ typename KERNEL_TYPE >
+ static real64
+ kernelLaunch( localIndex const numElems,
+ KERNEL_TYPE const & kernelComponent );
+
+protected:
+ /// The array containing the nodal position array.
+ arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const m_X;
+
+ /// The rank-global displacement array.
+ arrayView2d< real64 const, nodes::TOTAL_DISPLACEMENT_USD > const m_disp;
+
+ /// The rank-global incremental displacement array.
+ arrayView2d< real64 const, nodes::INCR_DISPLACEMENT_USD > const m_uhat;
+
+ /// The gravity vector.
+ real64 const m_gravityVector[3];
+
+ /// The rank global bulk density
+ arrayView2d< real64 const > const m_bulkDensity;
+
+ /// The rank-global fluid pressure arrays.
+ arrayView1d< real64 const > const m_pressure;
+ arrayView1d< real64 const > const m_pressure_n;
+
+ /// The rank-global initial temperature array
+ arrayView1d< real64 const > const m_initialTemperature;
+
+ /// The rank-global temperature arrays.
+ arrayView1d< real64 const > const m_temperature;
+ arrayView1d< real64 const > const m_temperature_n;
+
+ /// The rank-global mineral reaction molar increments arrays.
+ arrayView2d< real64 const, compflow::USD_COMP > const m_mineralReactionMolarIncrements;
+
+ /**
+ * @brief Get a parameter representative of the stiffness, used as physical scaling for the
+ * stabilization matrix.
+ * @param[in] k Element index.
+ * @return A parameter representative of the stiffness matrix dstress/dstrain
+ */
+ GEOS_HOST_DEVICE
+ GEOS_FORCE_INLINE
+ real64 computeStabilizationScaling( localIndex const k ) const
+ {
+ // TODO: generalize this to other constitutive models (currently we assume linear elasticity).
+ return 2.0 * m_constitutiveUpdate.getShearModulus( k );
+ }
+};
+
+/// The factory used to construct a ExplicitChemoMechanics kernel.
+using ExplicitChemoMechanicsFactory = finiteElement::KernelFactory< ExplicitChemoMechanics,
+ arrayView1d< globalIndex const > const,
+ globalIndex,
+ CRSMatrixView< real64, globalIndex const > const,
+ arrayView1d< real64 > const,
+ real64 const,
+ real64 const (&)[3] >;
+
+} // namespace solidMechanicsLagrangianFEMKernels
+
+} // namespace geos
+
+#include "finiteElement/kernelInterface/SparsityKernelBase.hpp"
+
+#endif // GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_KERNELS_EXPLICITCHEMOMECHANICS_HPP_
diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitChemoMechanics_impl.hpp b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitChemoMechanics_impl.hpp
new file mode 100644
index 00000000000..f8a943df746
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/ExplicitChemoMechanics_impl.hpp
@@ -0,0 +1,234 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 ExplicitChemoMechanics_impl.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_KERNELS_EXPLICITCHEMOMECHANICS_IMPL_HPP_
+#define GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_KERNELS_EXPLICITCHEMOMECHANICS_IMPL_HPP_
+
+#include "ExplicitChemoMechanics.hpp"
+#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp"
+#include "physicsSolvers/fluidFlow/SinglePhaseReactiveTransportFields.hpp"
+#include "physicsSolvers/multiphysics/PoromechanicsFields.hpp"
+#include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp"
+
+namespace geos
+{
+
+namespace solidMechanicsLagrangianFEMKernels
+{
+
+template< typename SUBREGION_TYPE,
+ typename CONSTITUTIVE_TYPE,
+ typename FE_TYPE >
+
+ExplicitChemoMechanics< SUBREGION_TYPE, CONSTITUTIVE_TYPE, FE_TYPE >::
+ExplicitChemoMechanics( NodeManager const & nodeManager,
+ EdgeManager const & edgeManager,
+ FaceManager const & faceManager,
+ localIndex const targetRegionIndex,
+ SUBREGION_TYPE const & elementSubRegion,
+ FE_TYPE const & finiteElementSpace,
+ CONSTITUTIVE_TYPE & inputConstitutiveType,
+ arrayView1d< globalIndex const > const inputDofNumber,
+ globalIndex const rankOffset,
+ CRSMatrixView< real64, globalIndex const > const inputMatrix,
+ arrayView1d< real64 > const inputRhs,
+ real64 const inputDt,
+ real64 const (&inputGravityVector)[3] ):
+ Base( nodeManager,
+ edgeManager,
+ faceManager,
+ targetRegionIndex,
+ elementSubRegion,
+ finiteElementSpace,
+ inputConstitutiveType,
+ inputDofNumber,
+ rankOffset,
+ inputMatrix,
+ inputRhs,
+ inputDt ),
+ m_X( nodeManager.referencePosition()),
+ m_disp( nodeManager.getField< fields::solidMechanics::totalDisplacement >() ),
+ m_uhat( nodeManager.getField< fields::solidMechanics::incrementalDisplacement >() ),
+ m_gravityVector{ inputGravityVector[0], inputGravityVector[1], inputGravityVector[2] },
+ m_bulkDensity( elementSubRegion.template getField< fields::poromechanics::bulkDensity >() ),
+ m_pressure( elementSubRegion.template getField< fields::flow::pressure >() ),
+ m_pressure_n( elementSubRegion.template getField< fields::flow::pressure_n >() ),
+ m_initialTemperature( elementSubRegion.template getField< fields::flow::initialTemperature >() ),
+ m_temperature( elementSubRegion.template getField< fields::flow::temperature >() ),
+ m_temperature_n( elementSubRegion.template getField< fields::flow::temperature_n >() ),
+ m_mineralReactionMolarIncrements( elementSubRegion.template getField< fields::flow::kineticReactionMolarIncrements >() )
+{}
+
+template< typename SUBREGION_TYPE,
+ typename CONSTITUTIVE_TYPE,
+ typename FE_TYPE >
+GEOS_HOST_DEVICE
+GEOS_FORCE_INLINE
+void ExplicitChemoMechanics< SUBREGION_TYPE, CONSTITUTIVE_TYPE, FE_TYPE >::
+setup( localIndex const k,
+ StackVariables & stack ) const
+{
+ m_finiteElementSpace.template setup< FE_TYPE >( k, m_meshData, stack.feStack );
+ localIndex const numSupportPoints =
+ m_finiteElementSpace.template numSupportPoints< FE_TYPE >( stack.feStack );
+ stack.numRows = 3 * numSupportPoints;
+ stack.numCols = stack.numRows;
+
+ for( localIndex a = 0; a < numSupportPoints; ++a )
+ {
+ localIndex const localNodeIndex = m_elemsToNodes( k, a );
+
+ for( int i = 0; i < 3; ++i )
+ {
+#if defined(CALC_FEM_SHAPE_IN_KERNEL)
+ stack.xLocal[ a ][ i ] = m_X[ localNodeIndex ][ i ];
+#endif
+ stack.u_local[ a ][i] = m_disp[ localNodeIndex ][i];
+ stack.uhat_local[ a ][i] = m_uhat[ localNodeIndex ][i];
+ stack.localRowDofIndex[a*3+i] = m_dofNumber[localNodeIndex]+i;
+ stack.localColDofIndex[a*3+i] = m_dofNumber[localNodeIndex]+i;
+ }
+ }
+
+ // Add stabilization to block diagonal parts of the local jacobian
+ // (this is a no-operation with FEM classes)
+ real64 const stabilizationScaling = computeStabilizationScaling( k );
+ m_finiteElementSpace.template addGradGradStabilizationMatrix
+ < FE_TYPE, numDofPerTrialSupportPoint, true >( stack.feStack,
+ stack.localJacobian,
+ -stabilizationScaling );
+}
+
+template< typename SUBREGION_TYPE,
+ typename CONSTITUTIVE_TYPE,
+ typename FE_TYPE >
+GEOS_HOST_DEVICE
+GEOS_FORCE_INLINE
+void ExplicitChemoMechanics< SUBREGION_TYPE, CONSTITUTIVE_TYPE, FE_TYPE >::
+quadraturePointKernel( localIndex const k,
+ localIndex const q,
+ StackVariables & stack ) const
+{
+ real64 dNdX[ numNodesPerElem ][ 3 ];
+ real64 const detJxW = m_finiteElementSpace.template getGradN< FE_TYPE >( k, q, stack.xLocal,
+ stack.feStack, dNdX );
+
+ real64 strainInc[6] = {0};
+ real64 totalStress[6] = {0};
+
+ typename CONSTITUTIVE_TYPE::KernelWrapper::DiscretizationOps stiffness;
+
+ FE_TYPE::symmetricGradient( dNdX, stack.uhat_local, strainInc );
+
+ // Evaluate total stress and its derivatives
+ // TODO: allow for a customization of the kernel to pass the average pressure to the small strain update (to account for cap pressure
+ // later)
+ m_constitutiveUpdate.smallStrainUpdateExplicitChemoMechanics( k, q,
+ m_dt,
+ m_pressure[k],
+ m_pressure_n[k],
+ m_temperature[k],
+ m_temperature_n[k],
+ m_initialTemperature[k],
+ m_mineralReactionMolarIncrements[k],
+ strainInc,
+ totalStress,
+ stiffness );
+
+ for( localIndex i=0; i<6; ++i )
+ {
+ totalStress[i] *= -detJxW;
+ }
+
+ // Here we consider the bodyForce is purely from the solid
+ // Warning: here, we lag (in iteration) the displacement dependence of bulkDensity
+ real64 const gravityForce[3] = { m_gravityVector[0] * m_bulkDensity( k, q )* detJxW,
+ m_gravityVector[1] * m_bulkDensity( k, q )* detJxW,
+ m_gravityVector[2] * m_bulkDensity( k, q )* detJxW };
+
+ real64 N[numNodesPerElem];
+ FE_TYPE::calcN( q, stack.feStack, N );
+ FE_TYPE::plusGradNajAijPlusNaFi( dNdX,
+ totalStress,
+ N,
+ gravityForce,
+ reinterpret_cast< real64 (&)[numNodesPerElem][3] >(stack.localResidual) );
+ real64 const stabilizationScaling = computeStabilizationScaling( k );
+ m_finiteElementSpace.template
+ addEvaluatedGradGradStabilizationVector< FE_TYPE,
+ numDofPerTrialSupportPoint >( stack.feStack,
+ stack.uhat_local,
+ reinterpret_cast< real64 (&)[numNodesPerElem][3] >(stack.localResidual),
+ -stabilizationScaling );
+ stiffness.template upperBTDB< numNodesPerElem >( dNdX, -detJxW, stack.localJacobian );
+}
+
+template< typename SUBREGION_TYPE,
+ typename CONSTITUTIVE_TYPE,
+ typename FE_TYPE >
+GEOS_HOST_DEVICE
+GEOS_FORCE_INLINE
+real64 ExplicitChemoMechanics< SUBREGION_TYPE, CONSTITUTIVE_TYPE, FE_TYPE >::
+complete( localIndex const k,
+ StackVariables & stack ) const
+{
+ GEOS_UNUSED_VAR( k );
+ real64 maxForce = 0;
+
+ // TODO: Does this work if BTDB is non-symmetric?
+ CONSTITUTIVE_TYPE::KernelWrapper::DiscretizationOps::template fillLowerBTDB< numNodesPerElem >( stack.localJacobian );
+ localIndex const numSupportPoints =
+ m_finiteElementSpace.template numSupportPoints< FE_TYPE >( stack.feStack );
+ for( int localNode = 0; localNode < numSupportPoints; ++localNode )
+ {
+ for( int dim = 0; dim < numDofPerTestSupportPoint; ++dim )
+ {
+ localIndex const dof =
+ LvArray::integerConversion< localIndex >( stack.localRowDofIndex[ numDofPerTestSupportPoint * localNode + dim ] - m_dofRankOffset );
+ if( dof < 0 || dof >= m_matrix.numRows() )
+ continue;
+ m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof,
+ stack.localRowDofIndex,
+ stack.localJacobian[ numDofPerTestSupportPoint * localNode + dim ],
+ stack.numRows );
+
+ RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[ dof ], stack.localResidual[ numDofPerTestSupportPoint * localNode + dim ] );
+ maxForce = fmax( maxForce, fabs( stack.localResidual[ numDofPerTestSupportPoint * localNode + dim ] ) );
+ }
+ }
+ return maxForce;
+}
+
+template< typename SUBREGION_TYPE,
+ typename CONSTITUTIVE_TYPE,
+ typename FE_TYPE >
+template< typename POLICY,
+ typename KERNEL_TYPE >
+real64
+ExplicitChemoMechanics< SUBREGION_TYPE, CONSTITUTIVE_TYPE, FE_TYPE >::kernelLaunch( localIndex const numElems,
+ KERNEL_TYPE const & kernelComponent )
+{
+ return Base::template kernelLaunch< POLICY, KERNEL_TYPE >( numElems, kernelComponent );
+}
+
+} // namespace solidMechanicsLagrangianFEMKernels
+
+} // namespace geos
+
+#endif // GEOS_PHYSICSSOLVERS_SOLIDMECHANICS_KERNELS_EXPLICITCHEMOMECHANICS_IMPL_HPP_
diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsExplicitChemoMechanicsKernels.cpp.template b/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsExplicitChemoMechanicsKernels.cpp.template
new file mode 100644
index 00000000000..a7fc5514a81
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/SolidMechanicsExplicitChemoMechanicsKernels.cpp.template
@@ -0,0 +1,38 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * 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 "physicsSolvers/solidMechanics/kernels/ExplicitChemoMechanics_impl.hpp"
+
+using ExplicitChemoMechanicsPolicy = @ExplicitChemoMechanicsPolicy@;
+
+#define INSTANTIATION( NAME )\
+template class NAME < @SUBREGION_TYPE@, @CONSTITUTIVE_TYPE@, @FE_TYPE@ >; \
+template real64 NAME < @SUBREGION_TYPE@, @CONSTITUTIVE_TYPE@, @FE_TYPE@ >::kernelLaunch< NAME##Policy, \
+ NAME < @SUBREGION_TYPE@, @CONSTITUTIVE_TYPE@, @FE_TYPE@ > > \
+ ( localIndex const, \
+ NAME < @SUBREGION_TYPE@, @CONSTITUTIVE_TYPE@, @FE_TYPE@ > const & ); \
+
+
+namespace geos
+{
+using namespace constitutive;
+using namespace finiteElement;
+namespace solidMechanicsLagrangianFEMKernels
+{
+ INSTANTIATION( ExplicitChemoMechanics )
+}
+}
+
+#undef INSTANTIATION
diff --git a/src/coreComponents/physicsSolvers/solidMechanics/kernels/policies.hpp.in b/src/coreComponents/physicsSolvers/solidMechanics/kernels/policies.hpp.in
index c14654cf0c7..bafc3a064b9 100644
--- a/src/coreComponents/physicsSolvers/solidMechanics/kernels/policies.hpp.in
+++ b/src/coreComponents/physicsSolvers/solidMechanics/kernels/policies.hpp.in
@@ -18,6 +18,7 @@
using ExplicitSmallStrainPolicy = @ExplicitSmallStrainPolicy@;
using ExplicitFiniteStrainPolicy = @ExplicitFiniteStrainPolicy@;
+using ExplicitChemoMechanicsPolicy = @ExplicitChemoMechanicsPolicy@;
using FixedStressThermoPoromechanicsPolicy = @FixedStressThermoPoromechanicsPolicy@;
using ImplicitSmallStrainNewmarkPolicy = @ImplicitSmallStrainNewmarkPolicy@;
using ImplicitSmallStrainQuasiStaticPolicy = @ImplicitSmallStrainQuasiStaticPolicy@;