20 #ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_HYDROSTATICPRESSUREKERNEL_HPP
21 #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_HYDROSTATICPRESSUREKERNEL_HPP
25 #include "common/GEOS_RAJA_Interface.hpp"
26 #include "constitutive/fluid/multifluid/MultiFluidBase.hpp"
32 namespace isothermalCompositionalMultiphaseBaseKernels
40 static real64 constexpr MIN_FOR_PHASE_PRESENCE = 1e-12;
41 static real64 constexpr MIN_FOR_COMP_PRESENCE = 1e-12;
45 FAILED_TO_CONVERGE = 0,
46 DETECTED_MULTIPHASE_FLOW = 1,
48 DETECTED_SINGLEPHASE_FLOW = 3,
49 PHASE_CORRECTION_NOT_NEEDED = 4
52 template<
typename FLUID_WRAPPER >
54 computeHydrostaticPressure(
integer const & numComps,
62 integer const maxNumEquilIterations,
63 real64 const & equilTolerance,
64 real64 const (&gravVector)[ 3 ],
65 FLUID_WRAPPER fluidWrapper,
68 real64 const & refElevation,
71 real64 const & newElevation,
85 StackArray<
real64, 4, constitutive::MultiFluidBase::MAX_NUM_PHASES *constitutive::MultiFluidBase::MAX_NUM_COMPONENTS,
86 constitutive::multifluid::LAYOUT_PHASE_COMP > phaseCompFrac( 1, 1, numPhases, numComps );
89 bool const isSinglePhaseInitialisation = phaseContacts.size() == 0;
91 bool isSinglePhaseFlow =
true;
95 real64 const gravCoef = gravVector[2] * ( refElevation - newElevation );
96 real64 const temperature = tempTableWrapper.
compute( &newElevation );
97 for(
integer ic = 0; ic < numComps; ++ic )
99 inputComposition[0][ic] = compFracTableWrappers[ic].compute( &newElevation );
105 for(
localIndex ip = 0; ip < numPhases; ++ip )
107 phasePressures[0][ip] = refPres[ip] - refPhaseMassDens[ip] * gravCoef;
111 integer const flashPhase = isSinglePhaseInitialisation ? ipInit :
112 evaluateFlashPhaseIndex( numPhases,
121 constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper,
122 phasePressures[0][flashPhase],
130 phaseInternalEnergy[0][0],
135 if( isSinglePhaseInitialisation )
137 for(
integer ic = 0; ic < numComps; ++ic )
139 compFrac[0][ic] = inputComposition[0][ic];
144 phaseCorrection( numComps,
148 phaseMinVolumeFraction,
149 phasePressures[0][flashPhase],
156 for(
localIndex ip = 0; ip < numPhases; ++ip )
158 phasePressures[1][ip] = refPres[ip] - 0.5 * ( refPhaseMassDens[ip] + phaseMassDens[0][0][ip] ) * gravCoef;
162 bool equilHasConverged =
false;
163 for(
integer eqIter = 0; eqIter < maxNumEquilIterations; ++eqIter )
166 real64 pressureError = 0.0;
167 for(
integer ip = 0; ip < numPhases; ++ip )
169 real64 const dp = LvArray::math::abs( phasePressures[0][ip] - phasePressures[1][ip] );
170 pressureError = LvArray::math::max( pressureError, dp );
171 phasePressures[0][ip] = phasePressures[1][ip];
173 equilHasConverged = ( pressureError < equilTolerance );
176 if( equilHasConverged )
182 constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper,
183 phasePressures[0][flashPhase],
191 phaseInternalEnergy[0][0],
194 for(
integer ip = 0; ip < numPhases; ++ip )
196 phasePressures[1][ip] = refPres[ip] - 0.5 * ( refPhaseMassDens[ip] + phaseMassDens[0][0][ip] ) * gravCoef;
203 for(
integer ip = 0; ip < numPhases; ++ip )
205 newPres[ip] = phasePressures[1][ip];
206 newPhaseMassDens[ip] = phaseMassDens[0][0][ip];
207 newPhaseDens[ip] = phaseDens[0][0][ip];
208 for(
integer ic = 0; ic < numComps; ++ic )
210 newPhaseCompFrac[ip][ic] = phaseCompFrac[0][0][ip][ic];
212 if( phaseFrac[0][0][ip] > MIN_FOR_PHASE_PRESENCE )
217 if( 1 < numberOfPhases )
219 isSinglePhaseFlow =
false;
222 if( !equilHasConverged )
224 return ReturnType::FAILED_TO_CONVERGE;
226 else if( !isSinglePhaseFlow )
228 return ReturnType::DETECTED_MULTIPHASE_FLOW;
232 return ReturnType::SUCCESS;
236 template<
typename FLUID_WRAPPER >
238 computeHydrostaticPressureAtMultipleElevations(
localIndex const & startElevationIndex,
248 integer const & maxNumEquilIterations,
249 real64 const & equilTolerance,
250 real64 const (&gravVector)[ 3 ],
251 FLUID_WRAPPER fluidWrapper,
261 localIndex const numEntries = LvArray::math::abs( startElevationIndex - endElevationIndex );
262 localIndex const step = ( endElevationIndex >= startElevationIndex ) ? 1 : -1;
263 ReturnType returnVal = ReturnType::SUCCESS;
264 forAll< serialPolicy >( numEntries, [=, &returnVal] (
localIndex const i )
266 localIndex const ref = startElevationIndex + i * step;
268 ReturnType
const iReturnVal =
269 computeHydrostaticPressure( numComps,
276 phaseMinVolumeFraction,
277 maxNumEquilIterations,
281 compFracTableWrappers,
283 elevationValues[0][ref],
284 pressureValues[ref][0],
286 elevationValues[0][next],
287 pressureValues[next][0],
290 phaseCompFrac[next][0] );
291 if( iReturnVal == ReturnType::FAILED_TO_CONVERGE )
293 returnVal = ReturnType::FAILED_TO_CONVERGE;
295 else if( iReturnVal == ReturnType::DETECTED_MULTIPHASE_FLOW )
297 returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW;
304 template<
typename FLUID_WRAPPER >
306 marchBetweenTwoElevations(
real64 const & startElevation,
307 real64 const & endElevation,
316 integer const maxNumEquilIterations,
317 real64 const & equilTolerance,
318 real64 const (&gravVector)[ 3 ],
319 FLUID_WRAPPER fluidWrapper,
331 evaluatePrimaryAndContactPhaseIndices( numPhases,
342 localIndex const iStart = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(),
343 elevationValues[0].size(),
346 localIndex const iEnd = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(),
347 elevationValues[0].size(),
350 ReturnType returnVal =
351 computeHydrostaticPressureAtMultipleElevations( iStart,
360 phaseMinVolumeFraction,
361 maxNumEquilIterations,
365 compFracTableWrappers,
379 computeHydrostaticPressure( numComps,
386 phaseMinVolumeFraction,
387 maxNumEquilIterations,
391 compFracTableWrappers,
393 elevationValues[0][iEnd],
394 pressureValues[iEnd][0],
398 endPhaseMassDens[0][0],
400 endPhaseCompFrac[0][0] );
402 real64 err = LvArray::math::abs( endPressure[0][0][ipCP] - endPressure[0][0][ipPP] ) / endPressure[0][0][ipPP];
403 int constexpr maxMarchIterations = 10;
404 real64 constexpr pressureTolerance = 1.0e-5;
407 for(
int marchIter = 1; marchIter < maxMarchIterations; ++marchIter )
409 if( err < pressureTolerance )
414 endPressure[0][0][ipCP] = endPressure[0][0][ipPP];
415 real64 const iStartPrimaryPressure = pressureValues[iStart][0][ipPP];
418 computeHydrostaticPressure( numComps,
425 phaseMinVolumeFraction,
426 maxNumEquilIterations,
430 compFracTableWrappers,
434 endPhaseMassDens[0][0],
435 elevationValues[0][iStart],
436 pressureValues[iStart][0],
437 phaseMassDens[iStart],
438 phaseDens[iStart][0],
439 phaseCompFrac[iStart][0] );
440 pressureValues[iStart][0][ipPP] = iStartPrimaryPressure;
443 computeHydrostaticPressureAtMultipleElevations( iStart,
452 phaseMinVolumeFraction,
453 maxNumEquilIterations,
457 compFracTableWrappers,
466 computeHydrostaticPressure( numComps,
473 phaseMinVolumeFraction,
474 maxNumEquilIterations,
478 compFracTableWrappers,
480 elevationValues[0][iEnd],
481 pressureValues[iEnd][0],
485 endPhaseMassDens[0][0],
487 endPhaseCompFrac[0][0] );
488 err = LvArray::math::abs( endPressure[0][0][ipCP] - endPressure[0][0][ipPP] ) / endPressure[0][0][ipPP];
494 template<
typename FLUID_WRAPPER >
503 integer const & maxNumEquilIterations,
506 real64 const equilTolerance,
507 real64 const (&gravVector)[ 3 ],
508 real64 const & datumElevation,
510 FLUID_WRAPPER fluidWrapper,
518 ReturnType returnVal = ReturnType::SUCCESS;
521 int const numContacts = phaseContacts.size();
522 bool const isSinglePhase = (numContacts == 0);
526 if( numContacts > 1 )
530 if( LvArray::math::abs( phaseContacts[1] - datumElevation ) <=
531 LvArray::math::abs( phaseContacts[0] - datumElevation ) )
540 for(
localIndex ip = 0; ip < numPhases; ++ip )
542 datumPresInput[0][0][ip] = datumPres;
546 real64 const datumTemp = tempTableWrapper.
compute( &datumElevation );
548 computeDatumPhaseMassDens( numComps,
552 phaseMinVolumeFraction,
557 compFracTableWrappers,
563 localIndex const iDatum = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(),
564 elevationValues[0].size(),
571 for(
integer ip = 0; ip < numPhases; ++ip )
573 datumPhaseMassDensTmp[ip] = datumPhaseMassDens[0][0][ip];
576 ReturnType
const iDatumReturnVal =
577 computeHydrostaticPressure( numComps,
584 phaseMinVolumeFraction,
585 maxNumEquilIterations,
589 compFracTableWrappers,
592 datumPresInput[0][0],
593 datumPhaseMassDensTmp,
594 elevationValues[0][iDatum],
595 pressureValues[iDatum][0],
596 phaseMassDens[iDatum],
597 phaseDens[iDatum][0],
598 phaseCompFrac[iDatum][0] );
599 if( iDatumReturnVal == ReturnType::FAILED_TO_CONVERGE )
601 return ReturnType::FAILED_TO_CONVERGE;
603 else if( iDatumReturnVal == ReturnType::DETECTED_MULTIPHASE_FLOW )
605 returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW;
611 returnVal = computeHydrostaticPressureAtMultipleElevations( iDatum,
620 phaseMinVolumeFraction,
621 maxNumEquilIterations,
625 compFracTableWrappers,
634 returnVal = computeHydrostaticPressureAtMultipleElevations( iDatum,
643 phaseMinVolumeFraction,
644 maxNumEquilIterations,
648 compFracTableWrappers,
658 integer iContactCloseIndex = iDatum;
660 integer iContactBottom = iDatum;
663 if( LvArray::math::abs( datumElevation - phaseContacts[iContactClose] ) > 1e-12 )
666 iContactCloseIndex = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(),
667 elevationValues[0].size(),
668 phaseContacts[iContactClose] );
671 returnVal = marchBetweenTwoElevations( datumElevation,
672 phaseContacts[iContactClose],
680 phaseMinVolumeFraction,
681 maxNumEquilIterations,
685 compFracTableWrappers,
694 integer iContactFarIndex = iContactCloseIndex;
696 if( iContactFar != -1 && LvArray::math::abs( phaseContacts[iContactClose] - phaseContacts[iContactFar] ) > 1e-12 )
699 iContactFarIndex = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(),
700 elevationValues[0].size(),
701 phaseContacts[iContactFar] );
704 returnVal = marchBetweenTwoElevations( phaseContacts[iContactClose],
705 phaseContacts[iContactFar],
713 phaseMinVolumeFraction,
714 maxNumEquilIterations,
718 compFracTableWrappers,
727 if( iContactFar == -1 )
729 iContactTop = iContactCloseIndex;
730 iContactBottom = iContactCloseIndex;
732 else if( phaseContacts[iContactClose] > phaseContacts[iContactFar] )
734 iContactTop = iContactCloseIndex;
735 iContactBottom = iContactFarIndex;
739 iContactTop = iContactFarIndex;
740 iContactBottom = iContactCloseIndex;
744 returnVal = computeHydrostaticPressureAtMultipleElevations( iContactTop,
753 phaseMinVolumeFraction,
754 maxNumEquilIterations,
758 compFracTableWrappers,
767 returnVal = computeHydrostaticPressureAtMultipleElevations( iContactBottom,
776 phaseMinVolumeFraction,
777 maxNumEquilIterations,
781 compFracTableWrappers,
792 template<
typename FLUID_WRAPPER >
794 phaseCorrection(
integer const & numComps,
804 FLUID_WRAPPER fluidWrapper )
810 bool phaseCorrectionNeeded =
false;
811 if( ipGas >= 0 && LvArray::math::abs( phaseFrac[ipGas] ) < MIN_FOR_PHASE_PRESENCE
812 && LvArray::math::abs( phaseMinVolumeFraction[ipGas] ) > MIN_FOR_PHASE_PRESENCE )
814 addedCompFrac[0][0] = 1.0;
816 ip_otherPhase = ipWater;
817 phaseCorrectionNeeded =
true;
827 if( ipWater >= 0 && LvArray::math::abs( phaseFrac[ipWater] ) < MIN_FOR_PHASE_PRESENCE
828 && LvArray::math::abs( phaseMinVolumeFraction[ipWater] ) > MIN_FOR_PHASE_PRESENCE )
830 addedCompFrac[0][1] = 1.0;
832 ip_otherPhase = ipGas;
833 phaseCorrectionNeeded =
true;
836 if( phaseCorrectionNeeded )
838 return applyPhaseCorrection( numComps,
853 compFrac[ic] = inputComposition[ic];
855 return ReturnType::PHASE_CORRECTION_NOT_NEEDED;
860 template<
typename FLUID_WRAPPER >
862 applyPhaseCorrection(
integer const & numComps,
871 FLUID_WRAPPER fluidWrapper )
887 real64 targetPhaseFrac = 1e-4;
889 for(
int iter = 0; iter < maxIters; ++iter )
891 a = ( a_high + a_low ) * 0.5;
892 mixingStep( numComps,
897 constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper,
906 phaseInternalEnergy[0][0],
909 err = ( phaseFrac[0][0][ip_phase] - targetPhaseFrac ) / targetPhaseFrac;
910 if( LvArray::math::abs( phaseFrac[0][0][ip_otherPhase] - 1.0 ) < MIN_FOR_PHASE_PRESENCE )
914 else if( LvArray::math::abs( phaseFrac[0][0][ip_phase] - 1.0 ) < MIN_FOR_PHASE_PRESENCE )
928 if( LvArray::math::abs( err ) < 1e-5 )
935 return ReturnType::SUCCESS;
938 static void mixingStep(
integer const & numComps,
947 compFrac[ic] = a * addedCompFrac[ic] + ( 1 - a ) * inputComposition[ic];
948 if( compFrac[ic] < MIN_FOR_COMP_PRESENCE )
960 static integer evaluateFlashPhaseIndex(
integer const & numPhases,
977 ipFP = ( ipGas >= 0 ) ? ipGas :
978 ( ipOil >= 0 ) ? ipOil :
979 ( ipWater >= 0 ) ? ipWater : 0;
982 else if( ipGas >= 0 && ipOil >= 0 && ipWater >= 0 )
985 real64 const goc = phaseContacts[1];
986 real64 const owc = phaseContacts[0];
993 else if( elevation > goc
994 || LvArray::math::abs( elevation - goc ) < 1e-12 )
999 else if( ipGas >= 0 && ipWater >= 0 )
1002 real64 const gwc = phaseContacts[0];
1005 || LvArray::math::abs( elevation - gwc ) < 1e-12 )
1010 else if( ipOil >= 0 && ipWater >= 0 )
1013 real64 const owc = phaseContacts[0];
1016 || LvArray::math::abs( elevation - owc ) < 1e-12 )
1021 else if( ipGas >= 0 && ipOil >= 0 )
1024 real64 const goc = phaseContacts[0];
1027 || LvArray::math::abs( elevation - goc ) < 1e-12 )
1035 static void evaluatePrimaryAndContactPhaseIndices(
integer const & numPhases,
1039 real64 const & startElevation,
1040 real64 const & endElevation,
1049 if( ipGas >= 0 && ipOil >= 0 && ipWater >= 0 )
1052 real64 const goc = phaseContacts[1];
1053 real64 const owc = phaseContacts[0];
1056 if( LvArray::math::abs( endElevation - owc ) < 1e-12
1057 && startElevation > owc )
1062 else if( LvArray::math::abs( endElevation - goc ) < 1e-12 )
1064 if( startElevation < goc )
1076 else if( ipGas >= 0 && ipWater >= 0 )
1079 real64 const gwc = phaseContacts[0];
1082 if( startElevation > gwc )
1088 else if( ipOil >= 0 && ipWater >= 0 )
1091 real64 const owc = phaseContacts[0];
1094 if( startElevation > owc )
1100 else if( ipGas >= 0 && ipOil >= 0 )
1103 real64 const goc = phaseContacts[0];
1106 if( startElevation > goc )
1116 template<
typename FLUID_WRAPPER >
1118 computeDatumPhaseMassDens(
integer const & numComps,
1123 real64 const & datumElevation,
1124 real64 const & datumPres,
1125 real64 const & datumTemp,
1129 FLUID_WRAPPER fluidWrapper )
1140 real64 datumTotalDens = 0.0;
1141 for(
integer ic = 0; ic < numComps; ++ic )
1143 datumInputComposition[0][ic] = compFracTableWrappers[ic].compute( &datumElevation );
1145 constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper,
1148 datumInputComposition[0],
1149 datumPhaseFrac[0][0],
1150 datumPhaseDens[0][0],
1151 datumPhaseMassDens[0][0],
1152 datumPhaseVisc[0][0],
1153 datumPhaseEnthalpy[0][0],
1154 datumPhaseInternalEnergy[0][0],
1155 datumPhaseCompFrac[0][0],
1163 ReturnType datumPhaseCorr = phaseCorrection( numComps,
1167 phaseMinVolumeFraction,
1170 datumInputComposition[0],
1171 datumPhaseFrac[0][0],
1174 if( datumPhaseCorr == ReturnType::SUCCESS )
1175 constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper,
1179 datumPhaseFrac[0][0],
1180 datumPhaseDens[0][0],
1181 datumPhaseMassDens[0][0],
1182 datumPhaseVisc[0][0],
1183 datumPhaseEnthalpy[0][0],
1184 datumPhaseInternalEnergy[0][0],
1185 datumPhaseCompFrac[0][0],
GEOS_HOST_DEVICE real64 compute(IN_ARRAY const &input) const
Interpolate in the table.
ArrayView< T, 1 > arrayView1d
Alias for 1D array view.
Array< T, 2, PERMUTATION > array2d
Alias for 2D array.
Array< T, 3, PERMUTATION > array3d
Alias for 3D array.
LvArray::StackArray< T, NDIM, PERMUTATION, localIndex, MAXSIZE > StackArray
Multidimensional stack-based array type. See LvArray:StackArray for details.
ArraySlice< T, 2, USD > arraySlice2d
Alias for 2D array slice.
double real64
64-bit floating point type.
GEOS_LOCALINDEX_TYPE localIndex
Local index type (for indexing objects within an MPI partition).
ArraySlice< T, 1, USD > arraySlice1d
Alias for 1D array slice.
Array< T, 4, PERMUTATION > array4d
Alias for 4D array.
ArrayView< T, 4, USD > arrayView4d
Alias for 4D array view.
ArrayView< T, 2, USD > arrayView2d
Alias for 2D array view.
int integer
Signed integer type.
Array< T, 1 > array1d
Alias for 1D array.
ArrayView< T, 3, USD > arrayView3d
Alias for 3D array view.