29#ifndef OPM_CHI_FLASH_HPP
30#define OPM_CHI_FLASH_HPP
44#include <dune/common/fvector.hh>
45#include <dune/common/fmatrix.hh>
46#include <dune/common/version.hh>
47#include <dune/common/classname.hh>
61template <
class Scalar,
class Flu
idSystem>
64 enum { numPhases = FluidSystem::numPhases };
65 enum { numComponents = FluidSystem::numComponents };
66 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx};
67 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx};
68 enum { numMiscibleComponents = FluidSystem::numMiscibleComponents};
69 enum { numMisciblePhases = FluidSystem::numMisciblePhases};
73 numMisciblePhases*numMiscibleComponents
81 template <
class Flu
idState>
82 static void solve(FluidState& fluid_state,
83 const Dune::FieldVector<typename FluidState::Scalar, numComponents>& z,
85 std::string twoPhaseMethod,
86 Scalar tolerance = -1.,
90 using InputEval =
typename FluidState::Scalar;
91 using ComponentVector = Dune::FieldVector<typename FluidState::Scalar, numComponents>;
93#if ! DUNE_VERSION_NEWER(DUNE_COMMON, 2,7)
94 Dune::FMatrixPrecision<InputEval>::set_singular_limit(1e-35);
97 tolerance = std::min<Scalar>(1e-3, 1e8 * std::numeric_limits<Scalar>::epsilon());
102 for(
int compIdx = 0; compIdx < numComponents; ++compIdx) {
103 K[compIdx] = fluid_state.K(compIdx);
110 if (verbosity >= 1) {
111 std::cout <<
"********" << std::endl;
112 std::cout <<
"Flash calculations on Cell " << spatialIdx << std::endl;
113 std::cout <<
"Inputs are K = [" << K <<
"], L = [" << L <<
"], z = [" << z <<
"], P = " << fluid_state.pressure(0) <<
", and T = " << fluid_state.temperature(0) << std::endl;
116 using ScalarVector = Dune::FieldVector<Scalar, numComponents>;
118 ScalarVector z_scalar;
119 ScalarVector K_scalar;
120 for (
unsigned i = 0; i < numComponents; ++i) {
125 ScalarFluidState fluid_state_scalar;
127 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
128 fluid_state_scalar.setMoleFraction(oilPhaseIdx, compIdx,
Opm::getValue(fluid_state.moleFraction(oilPhaseIdx, compIdx)));
129 fluid_state_scalar.setMoleFraction(gasPhaseIdx, compIdx,
Opm::getValue(fluid_state.moleFraction(gasPhaseIdx, compIdx)));
130 fluid_state_scalar.setKvalue(compIdx,
Opm::getValue(fluid_state.K(compIdx)));
133 fluid_state_scalar.setLvalue(L_scalar);
135 fluid_state_scalar.setPressure(FluidSystem::oilPhaseIdx,
136 Opm::getValue(fluid_state.pressure(FluidSystem::oilPhaseIdx)));
137 fluid_state_scalar.setPressure(FluidSystem::gasPhaseIdx,
138 Opm::getValue(fluid_state.pressure(FluidSystem::gasPhaseIdx)));
140 fluid_state_scalar.setTemperature(
Opm::getValue(fluid_state.temperature(0)));
143 bool is_stable =
false;
144 if ( L <= 0 || L == 1 ) {
145 if (verbosity >= 1) {
146 std::cout <<
"Perform stability test (L <= 0 or L == 1)!" << std::endl;
150 if (verbosity >= 1) {
151 std::cout <<
"Inputs after stability test are K = [" << K_scalar <<
"], L = [" << L_scalar <<
"], z = [" << z_scalar <<
"], P = " << fluid_state.pressure(0) <<
", and T = " << fluid_state.temperature(0) << std::endl;
155 const bool is_single_phase = is_stable;
158 if ( !is_single_phase ) {
161 flash_2ph(z_scalar, twoPhaseMethod, K_scalar, L_scalar, fluid_state_scalar, verbosity);
166 fluid_state_scalar.setLvalue(L_scalar);
169 if (verbosity >= 1) {
170 std::cout <<
"********" << std::endl;
175 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
176 const auto x_i = fluid_state_scalar.moleFraction(oilPhaseIdx, compIdx);
177 fluid_state.setMoleFraction(oilPhaseIdx, compIdx, x_i);
178 const auto y_i = fluid_state_scalar.moleFraction(gasPhaseIdx, compIdx);
179 fluid_state.setMoleFraction(gasPhaseIdx, compIdx, y_i);
182 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
183 fluid_state.setKvalue(compIdx, K_scalar[compIdx]);
184 fluid_state_scalar.setKvalue(compIdx, K_scalar[compIdx]);
186 fluid_state.setLvalue(L_scalar);
198 template <
class Flu
idState,
class ComponentVector>
199 static void solve(FluidState& fluid_state,
200 const ComponentVector& globalMolarities,
201 Scalar tolerance = 0.0)
205 using MaterialLawParams =
typename MaterialLaw::Params;
207 MaterialLawParams matParams;
208 solve<MaterialLaw>(fluid_state, matParams, globalMolarities, tolerance);
214 template <
class FlashFlu
idState>
215 static typename FlashFluidState::Scalar
wilsonK_(
const FlashFluidState& fluid_state,
int compIdx)
217 const auto& acf = FluidSystem::acentricFactor(compIdx);
218 const auto& T_crit = FluidSystem::criticalTemperature(compIdx);
219 const auto& T = fluid_state.temperature(0);
220 const auto& p_crit = FluidSystem::criticalPressure(compIdx);
221 const auto& p = fluid_state.pressure(0);
223 const auto& tmp =
Opm::exp(5.3727 * (1+acf) * (1-T_crit/T)) * (p_crit/p);
227 template <
class Vector,
class FlashFlu
idState>
228 static typename Vector::field_type
li_single_phase_label_(
const FlashFluidState& fluid_state,
const Vector& z,
int verbosity)
231 typename Vector::field_type sumVz = 0.0;
232 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
234 const auto& V_crit = FluidSystem::criticalVolume(compIdx);
237 sumVz += (V_crit * z[compIdx]);
241 typename Vector::field_type Tc_est = 0.0;
242 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
244 const auto& V_crit = FluidSystem::criticalVolume(compIdx);
245 const auto& T_crit = FluidSystem::criticalTemperature(compIdx);
248 Tc_est += (V_crit * T_crit * z[compIdx] / sumVz);
252 const auto& T = fluid_state.temperature(0);
255 typename Vector::field_type L;
261 if (verbosity >= 1) {
262 std::cout <<
"Cell is single-phase, liquid (L = 1.0) due to Li's phase labeling method giving T < Tc_est (" << T <<
" < " << Tc_est <<
")!" << std::endl;
270 if (verbosity >= 1) {
271 std::cout <<
"Cell is single-phase, vapor (L = 0.0) due to Li's phase labeling method giving T >= Tc_est (" << T <<
" >= " << Tc_est <<
")!" << std::endl;
279 template <
class Vector>
280 static typename Vector::field_type
rachfordRice_g_(
const Vector& K,
typename Vector::field_type L,
const Vector& z)
282 typename Vector::field_type g=0;
283 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
284 g += (z[compIdx]*(K[compIdx]-1))/(K[compIdx]-L*(K[compIdx]-1));
289 template <
class Vector>
290 static typename Vector::field_type
rachfordRice_dg_dL_(
const Vector& K,
const typename Vector::field_type L,
const Vector& z)
292 typename Vector::field_type dg=0;
293 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
294 dg += (z[compIdx]*(K[compIdx]-1)*(K[compIdx]-1))/((K[compIdx]-L*(K[compIdx]-1))*(K[compIdx]-L*(K[compIdx]-1)));
299 template <
class Vector>
304 typename Vector::field_type Kmin = K[0];
305 typename Vector::field_type Kmax = K[0];
306 for (
int compIdx=1; compIdx<numComponents; ++compIdx){
307 if (K[compIdx] < Kmin)
309 else if (K[compIdx] >= Kmax)
314 auto Lmin = (Kmin / (Kmin - 1));
315 auto Lmax = Kmax / (Kmax - 1);
326 auto L = (Lmin + Lmax)/2;
329 if (verbosity == 3 || verbosity == 4) {
330 std::cout <<
"Initial guess: L = " << L <<
" and [Lmin, Lmax] = [" << Lmin <<
", " << Lmax <<
"]" << std::endl;
331 std::cout << std::setw(10) <<
"Iteration" << std::setw(16) <<
"abs(step)" << std::setw(16) <<
"L" << std::endl;
335 for (
int iteration=1; iteration<100; ++iteration){
341 auto delta = g/dg_dL;
345 if (L < Lmin || L > Lmax)
348 if (verbosity == 3 || verbosity == 4) {
349 std::cout <<
"L is not within the the range [Lmin, Lmax], solve using Bisection method!" << std::endl;
359 if (verbosity >= 1) {
360 std::cout <<
"Rachford-Rice (Bisection) converged to final solution L = " << L << std::endl;
366 if (verbosity == 3 || verbosity == 4) {
367 std::cout << std::setw(10) << iteration << std::setw(16) <<
Opm::abs(delta) << std::setw(16) << L << std::endl;
375 if (verbosity >= 1) {
376 std::cout <<
"Rachford-Rice converged to final solution L = " << L << std::endl;
382 throw std::runtime_error(
" Rachford-Rice did not converge within maximum number of iterations" );
385 template <
class Vector>
386 static typename Vector::field_type
bisection_g_(
const Vector& K,
typename Vector::field_type Lmin,
387 typename Vector::field_type Lmax,
const Vector& z,
int verbosity)
393 if (verbosity >= 3) {
394 std::cout << std::setw(10) <<
"Iteration" << std::setw(16) <<
"g(Lmid)" << std::setw(16) <<
"L" << std::endl;
397 constexpr int max_it = 100;
399 for (
int iteration = 0; iteration < max_it; ++iteration){
401 auto L = (Lmin + Lmax) / 2;
403 if (verbosity == 3 || verbosity == 4) {
404 std::cout << std::setw(10) << iteration << std::setw(16) << gMid << std::setw(16) << L << std::endl;
413 else if (Dune::sign(gMid) != Dune::sign(gLmin)) {
423 throw std::runtime_error(
" Rachford-Rice with bisection failed with " + std::to_string(max_it) +
" iterations!");
426 template <
class FlashFlu
idState,
class ComponentVector>
427 static void phaseStabilityTest_(
bool& isStable, ComponentVector& K, FlashFluidState& fluid_state,
const ComponentVector& z,
int verbosity)
430 bool isTrivialL, isTrivialV;
431 ComponentVector x, y;
432 typename FlashFluidState::Scalar S_l, S_v;
433 ComponentVector K0 = K;
434 ComponentVector K1 = K;
437 if (verbosity == 3 || verbosity == 4) {
438 std::cout <<
"Stability test for vapor phase:" << std::endl;
440 checkStability_(fluid_state, isTrivialV, K0, y, S_v, z,
true, verbosity);
441 bool V_unstable = (S_v < (1.0 + 1e-5)) || isTrivialV;
444 if (verbosity == 3 || verbosity == 4) {
445 std::cout <<
"Stability test for liquid phase:" << std::endl;
447 checkStability_(fluid_state, isTrivialL, K1, x, S_l, z,
false, verbosity);
448 bool L_stable = (S_l < (1.0 + 1e-5)) || isTrivialL;
451 isStable = L_stable && V_unstable;
455 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
456 fluid_state.setMoleFraction(gasPhaseIdx, compIdx, z[compIdx]);
457 fluid_state.setMoleFraction(oilPhaseIdx, compIdx, z[compIdx]);
462 for (
int compIdx = 0; compIdx<numComponents; ++compIdx) {
463 K[compIdx] = y[compIdx] / x[compIdx];
468 template <
class FlashFlu
idState,
class ComponentVector>
469 static void checkStability_(
const FlashFluidState& fluid_state,
bool& isTrivial, ComponentVector& K, ComponentVector& xy_loc,
470 typename FlashFluidState::Scalar& S_loc,
const ComponentVector& z,
bool isGas,
int verbosity)
472 using FlashEval =
typename FlashFluidState::Scalar;
476 FlashFluidState fluid_state_fake = fluid_state;
477 FlashFluidState fluid_state_global = fluid_state;
480 if (verbosity >= 3 || verbosity >= 4) {
481 std::cout << std::setw(10) <<
"Iteration" << std::setw(16) <<
"K-Norm" << std::setw(16) <<
"R-Norm" << std::endl;
486 for (
int i = 0; i < 20000; ++i) {
489 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
490 xy_loc[compIdx] = K[compIdx] * z[compIdx];
491 S_loc += xy_loc[compIdx];
493 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
494 xy_loc[compIdx] /= S_loc;
495 fluid_state_fake.setMoleFraction(gasPhaseIdx, compIdx, xy_loc[compIdx]);
499 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
500 xy_loc[compIdx] = z[compIdx]/K[compIdx];
501 S_loc += xy_loc[compIdx];
503 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
504 xy_loc[compIdx] /= S_loc;
505 fluid_state_fake.setMoleFraction(oilPhaseIdx, compIdx, xy_loc[compIdx]);
509 int phaseIdx = (isGas ?
static_cast<int>(gasPhaseIdx) :
static_cast<int>(oilPhaseIdx));
510 int phaseIdx2 = (isGas ?
static_cast<int>(oilPhaseIdx) :
static_cast<int>(gasPhaseIdx));
512 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
513 fluid_state_global.setMoleFraction(phaseIdx2, compIdx, z[compIdx]);
516 typename FluidSystem::template ParameterCache<FlashEval> paramCache_fake;
517 paramCache_fake.updatePhase(fluid_state_fake, phaseIdx);
519 typename FluidSystem::template ParameterCache<FlashEval> paramCache_global;
520 paramCache_global.updatePhase(fluid_state_global, phaseIdx2);
523 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
527 fluid_state_fake.setFugacityCoefficient(phaseIdx, compIdx, phiFake);
528 fluid_state_global.setFugacityCoefficient(phaseIdx2, compIdx, phiGlobal);
533 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
535 auto fug_fake = fluid_state_fake.fugacity(phaseIdx, compIdx);
536 auto fug_global = fluid_state_global.fugacity(phaseIdx2, compIdx);
537 auto fug_ratio = fug_global / fug_fake;
538 R[compIdx] = fug_ratio / S_loc;
541 auto fug_fake = fluid_state_fake.fugacity(phaseIdx, compIdx);
542 auto fug_global = fluid_state_global.fugacity(phaseIdx2, compIdx);
543 auto fug_ratio = fug_fake / fug_global;
544 R[compIdx] = fug_ratio * S_loc;
548 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
549 K[compIdx] *= R[compIdx];
553 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
561 if (verbosity >= 3) {
562 std::cout << std::setw(10) << i << std::setw(16) << K_norm << std::setw(16) << R_norm << std::endl;
566 isTrivial = (K_norm < 1e-5);
567 if (isTrivial || R_norm < 1e-10)
572 throw std::runtime_error(
" Stability test did not converge");
576 template <
class FlashFlu
idState,
class ComponentVector>
577 static void computeLiquidVapor_(FlashFluidState& fluid_state,
typename FlashFluidState::Scalar& L, ComponentVector& K,
const ComponentVector& z)
582 typename FlashFluidState::Scalar sumx=0;
583 typename FlashFluidState::Scalar sumy=0;
584 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
585 x[compIdx] = z[compIdx]/(L + (1-L)*K[compIdx]);
587 y[compIdx] = (K[compIdx]*z[compIdx])/(L + (1-L)*K[compIdx]);
593 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
594 fluid_state.setMoleFraction(oilPhaseIdx, compIdx, x[compIdx]);
595 fluid_state.setMoleFraction(gasPhaseIdx, compIdx, y[compIdx]);
599 template <
class Flu
idState,
class ComponentVector>
601 const std::string& flash_2p_method,
602 ComponentVector& K_scalar,
603 typename FluidState::Scalar& L_scalar,
604 FluidState& fluid_state_scalar,
606 if (verbosity >= 1) {
607 std::cout <<
"Cell is two-phase! Solve Rachford-Rice with initial K = [" << K_scalar <<
"]" << std::endl;
612 if (flash_2p_method ==
"newton") {
613 if (verbosity >= 1) {
614 std::cout <<
"Calculate composition using Newton." << std::endl;
617 }
else if (flash_2p_method ==
"ssi") {
619 if (verbosity >= 1) {
620 std::cout <<
"Calculate composition using Succcessive Substitution." << std::endl;
623 }
else if (flash_2p_method ==
"ssi+newton") {
627 throw std::runtime_error(
"unknown two phase flash method " + flash_2p_method +
" is specified");
631 template <
class FlashFlu
idState,
class ComponentVector>
633 FlashFluidState& fluid_state,
const ComponentVector& z,
638 constexpr size_t num_equations = numMisciblePhases * numMiscibleComponents + 1;
639 constexpr size_t num_primary_variables = numMisciblePhases * numMiscibleComponents + 1;
640 using NewtonVector = Dune::FieldVector<Scalar, num_equations>;
641 using NewtonMatrix = Dune::FieldMatrix<Scalar, num_equations, num_primary_variables>;
642 constexpr Scalar tolerance = 1.e-8;
644 NewtonVector soln(0.);
645 NewtonVector res(0.);
646 NewtonMatrix jac (0.);
650 if (verbosity >= 1) {
651 std::cout <<
" the current L is " <<
Opm::getValue(L) << std::endl;
655 if (verbosity >= 1) {
656 std::cout <<
"Initial guess: x = [";
657 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
658 if (compIdx < numComponents - 1)
659 std::cout << fluid_state.moleFraction(oilPhaseIdx, compIdx) <<
" ";
661 std::cout << fluid_state.moleFraction(oilPhaseIdx, compIdx);
663 std::cout <<
"], y = [";
664 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
665 if (compIdx < numComponents - 1)
666 std::cout << fluid_state.moleFraction(gasPhaseIdx, compIdx) <<
" ";
668 std::cout << fluid_state.moleFraction(gasPhaseIdx, compIdx);
670 std::cout <<
"], and " <<
"L = " << L << std::endl;
674 if (verbosity == 2 || verbosity == 4) {
675 std::cout << std::setw(10) <<
"Iteration" << std::setw(16) <<
"Norm2(step)" << std::setw(16) <<
"Norm2(Residual)" << std::endl;
681 std::vector<Eval> x(numComponents), y(numComponents);
685 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
686 x[compIdx] = Eval(fluid_state.moleFraction(oilPhaseIdx, compIdx), compIdx);
687 const unsigned idx = compIdx + numComponents;
688 y[compIdx] = Eval(fluid_state.moleFraction(gasPhaseIdx, compIdx), idx);
690 l = Eval(L, num_primary_variables - 1);
694 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
695 flash_fluid_state.setMoleFraction(FluidSystem::oilPhaseIdx, compIdx, x[compIdx]);
696 flash_fluid_state.setMoleFraction(FluidSystem::gasPhaseIdx, compIdx, y[compIdx]);
698 flash_fluid_state.setKvalue(compIdx, y[compIdx] / x[compIdx]);
700 flash_fluid_state.setLvalue(l);
702 flash_fluid_state.setPressure(FluidSystem::oilPhaseIdx,
703 fluid_state.pressure(FluidSystem::oilPhaseIdx));
704 flash_fluid_state.setPressure(FluidSystem::gasPhaseIdx,
705 fluid_state.pressure(FluidSystem::gasPhaseIdx));
708 flash_fluid_state.setSaturation(FluidSystem::gasPhaseIdx,
709 fluid_state.saturation(FluidSystem::gasPhaseIdx));
710 flash_fluid_state.setSaturation(FluidSystem::oilPhaseIdx,
711 fluid_state.saturation(FluidSystem::oilPhaseIdx));
712 flash_fluid_state.setTemperature(fluid_state.temperature(0));
714 using ParamCache =
typename FluidSystem::template ParameterCache<typename CompositionalFluidState<Eval, FluidSystem>::Scalar>;
715 ParamCache paramCache;
717 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
718 paramCache.updatePhase(flash_fluid_state, phaseIdx);
719 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
721 Eval phi = FluidSystem::fugacityCoefficient(flash_fluid_state, paramCache, phaseIdx, compIdx);
722 flash_fluid_state.setFugacityCoefficient(phaseIdx, compIdx, phi);
725 bool converged =
false;
727 constexpr unsigned max_iter = 1000;
728 while (iter < max_iter) {
729 assembleNewton_<CompositionalFluidState<Eval, FluidSystem>, ComponentVector, num_primary_variables, num_equations>
730 (flash_fluid_state, z, jac, res);
731 if (verbosity >= 1) {
732 std::cout <<
" newton residual is " << res.two_norm() << std::endl;
734 converged = res.two_norm() < tolerance;
739 jac.solve(soln, res);
740 constexpr Scalar damping_factor = 1.0;
742 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
743 x[compIdx] -= soln[compIdx] * damping_factor;
744 y[compIdx] -= soln[compIdx + numComponents] * damping_factor;
746 l -= soln[num_equations - 1] * damping_factor;
748 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
749 flash_fluid_state.setMoleFraction(FluidSystem::oilPhaseIdx, compIdx, x[compIdx]);
750 flash_fluid_state.setMoleFraction(FluidSystem::gasPhaseIdx, compIdx, y[compIdx]);
752 flash_fluid_state.setKvalue(compIdx, y[compIdx] / x[compIdx]);
754 flash_fluid_state.setLvalue(l);
756 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
757 paramCache.updatePhase(flash_fluid_state, phaseIdx);
758 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
759 Eval phi = FluidSystem::fugacityCoefficient(flash_fluid_state, paramCache, phaseIdx, compIdx);
760 flash_fluid_state.setFugacityCoefficient(phaseIdx, compIdx, phi);
764 if (verbosity >= 1) {
765 for (
unsigned i = 0; i < num_equations; ++i) {
766 for (
unsigned j = 0; j < num_primary_variables; ++j) {
767 std::cout <<
" " << jac[i][j];
769 std::cout << std::endl;
771 std::cout << std::endl;
774 throw std::runtime_error(
" Newton composition update did not converge within maxIterations " + std::to_string(max_iter));
778 for (
unsigned idx = 0; idx < numComponents; ++idx) {
779 const auto x_i =
Opm::getValue(flash_fluid_state.moleFraction(oilPhaseIdx, idx));
780 fluid_state.setMoleFraction(FluidSystem::oilPhaseIdx, idx, x_i);
781 const auto y_i =
Opm::getValue(flash_fluid_state.moleFraction(gasPhaseIdx, idx));
782 fluid_state.setMoleFraction(FluidSystem::gasPhaseIdx, idx, y_i);
784 fluid_state.setKvalue(idx, K_i);
789 fluid_state.setLvalue(L);
793 template<
typename FlashFlu
idState,
typename ComponentVector,
size_t num_primary,
size_t num_equation >
795 const ComponentVector& global_composition,
796 Dune::FieldMatrix<double, num_equation, num_primary>& jac,
797 Dune::FieldVector<double, num_equation>& res)
800 std::vector<Eval> x(numComponents), y(numComponents);
801 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
802 x[compIdx] = fluid_state.moleFraction(oilPhaseIdx, compIdx);
803 y[compIdx] = fluid_state.moleFraction(gasPhaseIdx, compIdx);
805 const Eval& l = fluid_state.L();
809 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
812 auto local_res = -global_composition[compIdx] + l * x[compIdx] + (1 - l) * y[compIdx];
814 for (
unsigned i = 0; i < num_primary; ++i) {
815 jac[compIdx][i] = local_res.derivative(i);
821 auto local_res = (fluid_state.fugacity(oilPhaseIdx, compIdx) -
822 fluid_state.fugacity(gasPhaseIdx, compIdx));
824 for (
unsigned i = 0; i < num_primary; ++i) {
825 jac[compIdx + numComponents][i] = local_res.derivative(i);
832 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
836 auto local_res = sumx - sumy;
838 for (
unsigned i = 0; i < num_primary; ++i) {
839 jac[num_equation - 1][i] = local_res.derivative(i);
844 template<
typename FlashFlu
idState,
typename ComponentVector,
size_t num_primary,
size_t num_equation >
846 const ComponentVector& global_composition,
847 Dune::FieldMatrix<double, num_equation, num_primary>& jac,
848 Dune::FieldVector<double, num_equation>& res)
851 std::vector<Eval> x(numComponents), y(numComponents);
852 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
853 x[compIdx] = fluid_state.moleFraction(oilPhaseIdx, compIdx);
854 y[compIdx] = fluid_state.moleFraction(gasPhaseIdx, compIdx);
856 const Eval& l = fluid_state.L();
861 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
864 auto local_res = -global_composition[compIdx] + x[compIdx];
866 for (
unsigned i = 0; i < num_primary; ++i) {
867 jac[compIdx][i] = local_res.derivative(i);
873 auto local_res = -global_composition[compIdx] + y[compIdx];
875 for (
unsigned i = 0; i < num_primary; ++i) {
876 jac[compIdx + numComponents][i] = local_res.derivative(i);
882 const bool isGas =
Opm::abs(l - 1.0) > std::numeric_limits<double>::epsilon();
891 for (
unsigned i = 0; i < num_primary; ++i) {
892 jac[num_equation - 1][i] = local_res.derivative(i);
896 template <
typename FlashFlu
idStateScalar,
typename Flu
idState,
typename ComponentVector>
898 const ComponentVector& z,
899 FluidState& fluid_state,
900 bool is_single_phase)
909 template <
typename FlashFlu
idStateScalar,
typename Flu
idState,
typename ComponentVector>
911 const ComponentVector& z,
912 FluidState& fluid_state)
915 constexpr size_t num_equations = numMisciblePhases * numMiscibleComponents + 1;
916 constexpr size_t secondary_num_pv = numComponents + 1;
918 using SecondaryComponentVector = Dune::FieldVector<SecondaryEval, numComponents>;
921 SecondaryFlashFluidState secondary_fluid_state;
922 SecondaryComponentVector secondary_z;
925 const SecondaryEval sec_p = SecondaryEval(fluid_state_scalar.pressure(FluidSystem::oilPhaseIdx), 0);
926 secondary_fluid_state.setPressure(FluidSystem::oilPhaseIdx, sec_p);
927 secondary_fluid_state.setPressure(FluidSystem::gasPhaseIdx, sec_p);
930 secondary_fluid_state.setTemperature(
Opm::getValue(fluid_state_scalar.temperature(0)));
932 for (
unsigned idx = 0; idx < numComponents; ++idx) {
933 secondary_z[idx] = SecondaryEval(
Opm::getValue(z[idx]), idx + 1);
936 for (
unsigned idx = 0; idx < num_equations; ++idx) {
938 const auto x_i = fluid_state_scalar.moleFraction(oilPhaseIdx, idx);
939 secondary_fluid_state.setMoleFraction(FluidSystem::oilPhaseIdx, idx, x_i);
940 const auto y_i = fluid_state_scalar.moleFraction(gasPhaseIdx, idx);
941 secondary_fluid_state.setMoleFraction(FluidSystem::gasPhaseIdx, idx, y_i);
943 const auto K_i = fluid_state_scalar.K(idx);
944 secondary_fluid_state.setKvalue(idx, K_i);
946 const auto L = fluid_state_scalar.L();
947 secondary_fluid_state.setLvalue(L);
951 using SecondaryParamCache =
typename FluidSystem::template ParameterCache<typename SecondaryFlashFluidState::Scalar>;
952 SecondaryParamCache secondary_param_cache;
953 for (
unsigned phase_idx = 0; phase_idx < numPhases; ++phase_idx) {
954 secondary_param_cache.updatePhase(secondary_fluid_state, phase_idx);
955 for (
unsigned comp_idx = 0; comp_idx < numComponents; ++comp_idx) {
956 SecondaryEval phi = FluidSystem::fugacityCoefficient(secondary_fluid_state, secondary_param_cache, phase_idx, comp_idx);
957 secondary_fluid_state.setFugacityCoefficient(phase_idx, comp_idx, phi);
961 using SecondaryNewtonVector = Dune::FieldVector<Scalar, num_equations>;
962 using SecondaryNewtonMatrix = Dune::FieldMatrix<Scalar, num_equations, secondary_num_pv>;
963 SecondaryNewtonMatrix sec_jac;
964 SecondaryNewtonVector sec_res;
968 assembleNewton_<SecondaryFlashFluidState, SecondaryComponentVector, secondary_num_pv, num_equations>
969 (secondary_fluid_state, secondary_z, sec_jac, sec_res);
974 constexpr size_t primary_num_pv = numMisciblePhases * numMiscibleComponents + 1;
976 using PrimaryComponentVector = Dune::FieldVector<double, numComponents>;
979 PrimaryFlashFluidState primary_fluid_state;
981 PrimaryComponentVector primary_z;
982 for (
unsigned comp_idx = 0; comp_idx < numComponents; ++comp_idx) {
985 for (
unsigned comp_idx = 0; comp_idx < numComponents; ++comp_idx) {
986 const auto x_ii = PrimaryEval(fluid_state_scalar.moleFraction(oilPhaseIdx, comp_idx), comp_idx);
987 primary_fluid_state.setMoleFraction(oilPhaseIdx, comp_idx, x_ii);
988 const unsigned idx = comp_idx + numComponents;
989 const auto y_ii = PrimaryEval(fluid_state_scalar.moleFraction(gasPhaseIdx, comp_idx), idx);
990 primary_fluid_state.setMoleFraction(gasPhaseIdx, comp_idx, y_ii);
991 primary_fluid_state.setKvalue(comp_idx, y_ii / x_ii);
994 l = PrimaryEval(fluid_state_scalar.L(), primary_num_pv - 1);
995 primary_fluid_state.setLvalue(l);
996 primary_fluid_state.setPressure(oilPhaseIdx, fluid_state_scalar.pressure(oilPhaseIdx));
997 primary_fluid_state.setPressure(gasPhaseIdx, fluid_state_scalar.pressure(gasPhaseIdx));
998 primary_fluid_state.setTemperature(fluid_state_scalar.temperature(0));
1001 using PrimaryParamCache =
typename FluidSystem::template ParameterCache<typename PrimaryFlashFluidState::Scalar>;
1002 PrimaryParamCache primary_param_cache;
1003 for (
unsigned phase_idx = 0; phase_idx < numPhases; ++phase_idx) {
1004 primary_param_cache.updatePhase(primary_fluid_state, phase_idx);
1005 for (
unsigned comp_idx = 0; comp_idx < numComponents; ++comp_idx) {
1006 PrimaryEval phi = FluidSystem::fugacityCoefficient(primary_fluid_state, primary_param_cache, phase_idx, comp_idx);
1007 primary_fluid_state.setFugacityCoefficient(phase_idx, comp_idx, phi);
1011 using PrimaryNewtonVector = Dune::FieldVector<Scalar, num_equations>;
1012 using PrimaryNewtonMatrix = Dune::FieldMatrix<Scalar, num_equations, primary_num_pv>;
1013 PrimaryNewtonVector pri_res;
1014 PrimaryNewtonMatrix pri_jac;
1017 assembleNewton_<PrimaryFlashFluidState, PrimaryComponentVector, primary_num_pv, num_equations>
1018 (primary_fluid_state, primary_z, pri_jac, pri_res);
1024 sec_jac.template leftmultiply(pri_jac);
1026 using InputEval =
typename FluidState::Scalar;
1027 using ComponentVectorMoleFraction = Dune::FieldVector<InputEval, numComponents>;
1029 ComponentVectorMoleFraction x(numComponents), y(numComponents);
1030 InputEval L_eval = L;
1037 const auto p_l = fluid_state.pressure(FluidSystem::oilPhaseIdx);
1038 const auto p_v = fluid_state.pressure(FluidSystem::gasPhaseIdx);
1039 std::vector<double> K(numComponents);
1041 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
1042 K[compIdx] = fluid_state_scalar.K(compIdx);
1043 x[compIdx] = fluid_state_scalar.moleFraction(FluidSystem::oilPhaseIdx,compIdx);
1044 y[compIdx] = fluid_state_scalar.moleFraction(FluidSystem::gasPhaseIdx,compIdx);
1051 constexpr size_t num_deri = numComponents;
1052 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
1053 std::vector<double> deri(num_deri, 0.);
1055 for (
unsigned idx = 0; idx < num_deri; ++idx) {
1056 deri[idx] = -sec_jac[compIdx][0] * p_l.derivative(idx);
1059 for (
unsigned cIdx = 0; cIdx < numComponents; ++cIdx) {
1060 const double pz = -sec_jac[compIdx][cIdx + 1];
1061 const auto& zi = z[cIdx];
1062 for (
unsigned idx = 0; idx < num_deri; ++idx) {
1063 deri[idx] += pz * zi.derivative(idx);
1066 for (
unsigned idx = 0; idx < num_deri; ++idx) {
1067 x[compIdx].setDerivative(idx, deri[idx]);
1070 for (
unsigned idx = 0; idx < num_deri; ++idx) {
1071 deri[idx] = -sec_jac[compIdx + numComponents][0] * p_v.derivative(idx);
1073 for (
unsigned cIdx = 0; cIdx < numComponents; ++cIdx) {
1074 const double pz = -sec_jac[compIdx + numComponents][cIdx + 1];
1075 const auto& zi = z[cIdx];
1076 for (
unsigned idx = 0; idx < num_deri; ++idx) {
1077 deri[idx] += pz * zi.derivative(idx);
1080 for (
unsigned idx = 0; idx < num_deri; ++idx) {
1081 y[compIdx].setDerivative(idx, deri[idx]);
1085 std::vector<double> deriL(num_deri, 0.);
1086 for (
unsigned idx = 0; idx < num_deri; ++idx) {
1087 deriL[idx] = -sec_jac[2 * numComponents][0] * p_v.derivative(idx);
1089 for (
unsigned cIdx = 0; cIdx < numComponents; ++cIdx) {
1090 const double pz = -sec_jac[2 * numComponents][cIdx + 1];
1091 const auto& zi = z[cIdx];
1092 for (
unsigned idx = 0; idx < num_deri; ++idx) {
1093 deriL[idx] += pz * zi.derivative(idx);
1097 for (
unsigned idx = 0; idx < num_deri; ++idx) {
1098 L_eval.setDerivative(idx, deriL[idx]);
1103 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
1104 fluid_state.setMoleFraction(FluidSystem::oilPhaseIdx, compIdx, x[compIdx]);
1105 fluid_state.setMoleFraction(FluidSystem::gasPhaseIdx, compIdx, y[compIdx]);
1107 fluid_state.setLvalue(L_eval);
1110 template <
typename FlashFlu
idStateScalar,
typename Flu
idState,
typename ComponentVector>
1112 const ComponentVector& z,
1113 FluidState& fluid_state)
1115 using InputEval =
typename FluidState::Scalar;
1117 InputEval L_eval = fluid_state_scalar.L();;
1121 for (
unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
1122 fluid_state.setMoleFraction(FluidSystem::oilPhaseIdx, compIdx, z[compIdx]);
1123 fluid_state.setMoleFraction(FluidSystem::gasPhaseIdx, compIdx, z[compIdx]);
1125 fluid_state.setLvalue(L_eval);
1130 template <
class FlashFlu
idState,
class ComponentVector>
1132 const bool newton_afterwards,
const int verbosity)
1135 const int maxIterations = newton_afterwards ? 3 : 10;
1138 std::ios_base::fmtflags f(std::cout.flags());
1142 std::cout <<
"Initial guess: K = [" << K <<
"] and L = " << L << std::endl;
1144 if (verbosity == 2 || verbosity == 4) {
1146 int fugWidth = (numComponents * 12)/2;
1147 int convWidth = fugWidth + 7;
1148 std::cout << std::setw(10) <<
"Iteration" << std::setw(fugWidth) <<
"fL/fV" << std::setw(convWidth) <<
"norm2(fL/fv-1)" << std::endl;
1153 for (
int i=0; i < maxIterations; ++i){
1158 using ParamCache =
typename FluidSystem::template ParameterCache<typename FlashFluidState::Scalar>;
1159 ParamCache paramCache;
1160 for (
int phaseIdx=0; phaseIdx<numPhases; ++phaseIdx){
1161 paramCache.updatePhase(fluid_state, phaseIdx);
1162 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
1163 auto phi = FluidSystem::fugacityCoefficient(fluid_state, paramCache, phaseIdx, compIdx);
1164 fluid_state.setFugacityCoefficient(phaseIdx, compIdx, phi);
1169 ComponentVector newFugRatio;
1170 ComponentVector convFugRatio;
1171 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
1172 newFugRatio[compIdx] = fluid_state.fugacity(oilPhaseIdx, compIdx)/fluid_state.fugacity(gasPhaseIdx, compIdx);
1173 convFugRatio[compIdx] = newFugRatio[compIdx] - 1.0;
1177 if (verbosity == 2 || verbosity == 4) {
1179 int fugWidth = (prec + 3);
1180 int convWidth = prec + 9;
1181 std::cout << std::defaultfloat;
1182 std::cout << std::fixed;
1183 std::cout << std::setw(5) << i;
1184 std::cout << std::setw(fugWidth);
1185 std::cout << std::setprecision(prec);
1186 std::cout << newFugRatio;
1187 std::cout << std::scientific;
1188 std::cout << std::setw(convWidth) << convFugRatio.two_norm() << std::endl;
1192 if (convFugRatio.two_norm() < 1e-6){
1197 if (verbosity >= 1) {
1198 std::cout <<
"Solution converged to the following result :" << std::endl;
1199 std::cout <<
"x = [";
1200 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
1201 if (compIdx < numComponents - 1)
1202 std::cout << fluid_state.moleFraction(oilPhaseIdx, compIdx) <<
" ";
1204 std::cout << fluid_state.moleFraction(oilPhaseIdx, compIdx);
1206 std::cout <<
"]" << std::endl;
1207 std::cout <<
"y = [";
1208 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
1209 if (compIdx < numComponents - 1)
1210 std::cout << fluid_state.moleFraction(gasPhaseIdx, compIdx) <<
" ";
1212 std::cout << fluid_state.moleFraction(gasPhaseIdx, compIdx);
1214 std::cout <<
"]" << std::endl;
1215 std::cout <<
"K = [" << K <<
"]" << std::endl;
1216 std::cout <<
"L = " << L << std::endl;
1225 for (
int compIdx=0; compIdx<numComponents; ++compIdx){
1226 K[compIdx] *= newFugRatio[compIdx];
1234 if (!newton_afterwards) {
1235 throw std::runtime_error(
1236 "Successive substitution composition update did not converge within maxIterations");
Represents all relevant thermodynamic quantities of a multi-phase, multi-component fluid system assum...
Representation of an evaluation of a function and its derivatives w.r.t. a set of variables in the lo...
Provides the opm-material specific exception classes.
This file contains helper classes for the material laws.
A number of commonly used algebraic functions for the localized OPM automatic differentiation (AD) fr...
Some templates to wrap the valgrind client request macros.
Represents all relevant thermodynamic quantities of a multi-phase, multi-component fluid system assum...
Definition: CompositionalFluidState.hpp:46
Represents a function evaluation and its derivatives w.r.t. a fixed set of variables.
Definition: Evaluation.hpp:59
Implements a dummy linear saturation-capillary pressure relation which just disables capillary pressu...
Definition: NullMaterial.hpp:46
A generic traits class which does not provide any indices.
Definition: MaterialTraits.hpp:45
Determines the phase compositions, pressures and saturations given the total mass of all components f...
Definition: PTFlash.hpp:63
static void updateDerivativesTwoPhase_(const FlashFluidStateScalar &fluid_state_scalar, const ComponentVector &z, FluidState &fluid_state)
Definition: PTFlash.hpp:910
static Vector::field_type rachfordRice_dg_dL_(const Vector &K, const typename Vector::field_type L, const Vector &z)
Definition: PTFlash.hpp:290
static void successiveSubstitutionComposition_(ComponentVector &K, typename ComponentVector::field_type &L, FlashFluidState &fluid_state, const ComponentVector &z, const bool newton_afterwards, const int verbosity)
Definition: PTFlash.hpp:1131
static void updateDerivatives_(const FlashFluidStateScalar &fluid_state_scalar, const ComponentVector &z, FluidState &fluid_state, bool is_single_phase)
Definition: PTFlash.hpp:897
static Vector::field_type bisection_g_(const Vector &K, typename Vector::field_type Lmin, typename Vector::field_type Lmax, const Vector &z, int verbosity)
Definition: PTFlash.hpp:386
static void phaseStabilityTest_(bool &isStable, ComponentVector &K, FlashFluidState &fluid_state, const ComponentVector &z, int verbosity)
Definition: PTFlash.hpp:427
static Vector::field_type li_single_phase_label_(const FlashFluidState &fluid_state, const Vector &z, int verbosity)
Definition: PTFlash.hpp:228
static FlashFluidState::Scalar wilsonK_(const FlashFluidState &fluid_state, int compIdx)
Definition: PTFlash.hpp:215
static void assembleNewtonSingle_(const FlashFluidState &fluid_state, const ComponentVector &global_composition, Dune::FieldMatrix< double, num_equation, num_primary > &jac, Dune::FieldVector< double, num_equation > &res)
Definition: PTFlash.hpp:845
static void computeLiquidVapor_(FlashFluidState &fluid_state, typename FlashFluidState::Scalar &L, ComponentVector &K, const ComponentVector &z)
Definition: PTFlash.hpp:577
static void assembleNewton_(const FlashFluidState &fluid_state, const ComponentVector &global_composition, Dune::FieldMatrix< double, num_equation, num_primary > &jac, Dune::FieldVector< double, num_equation > &res)
Definition: PTFlash.hpp:794
static void newtonComposition_(ComponentVector &K, typename FlashFluidState::Scalar &L, FlashFluidState &fluid_state, const ComponentVector &z, int verbosity)
Definition: PTFlash.hpp:632
static Vector::field_type rachfordRice_g_(const Vector &K, typename Vector::field_type L, const Vector &z)
Definition: PTFlash.hpp:280
static void solve(FluidState &fluid_state, const Dune::FieldVector< typename FluidState::Scalar, numComponents > &z, int spatialIdx, std::string twoPhaseMethod, Scalar tolerance=-1., int verbosity=0)
Calculates the fluid state from the global mole fractions of the components and the phase pressures.
Definition: PTFlash.hpp:82
static void checkStability_(const FlashFluidState &fluid_state, bool &isTrivial, ComponentVector &K, ComponentVector &xy_loc, typename FlashFluidState::Scalar &S_loc, const ComponentVector &z, bool isGas, int verbosity)
Definition: PTFlash.hpp:469
static void flash_2ph(const ComponentVector &z_scalar, const std::string &flash_2p_method, ComponentVector &K_scalar, typename FluidState::Scalar &L_scalar, FluidState &fluid_state_scalar, int verbosity=0)
Definition: PTFlash.hpp:600
static void updateDerivativesSinglePhase_(const FlashFluidStateScalar &fluid_state_scalar, const ComponentVector &z, FluidState &fluid_state)
Definition: PTFlash.hpp:1111
static void solve(FluidState &fluid_state, const ComponentVector &globalMolarities, Scalar tolerance=0.0)
Calculates the chemical equilibrium from the component fugacities in a phase.
Definition: PTFlash.hpp:199
static Vector::field_type solveRachfordRice_g_(const Vector &K, const Vector &z, int verbosity)
Definition: PTFlash.hpp:300
Implements the Peng-Robinson equation of state for a mixture.
Definition: PengRobinsonMixture.hpp:41
static LhsEval computeFugacityCoefficient(const FluidState &fs, const Params ¶ms, unsigned phaseIdx, unsigned compIdx)
Returns the fugacity coefficient of an individual component in the phase.
Definition: PengRobinsonMixture.hpp:89
Definition: Air_Mesitylene.hpp:34
Evaluation exp(const Evaluation &value)
Definition: MathToolbox.hpp:403
ReturnEval_< Evaluation1, Evaluation2 >::type min(const Evaluation1 &arg1, const Evaluation2 &arg2)
Definition: MathToolbox.hpp:346
ReturnEval_< Evaluation1, Evaluation2 >::type max(const Evaluation1 &arg1, const Evaluation2 &arg2)
Definition: MathToolbox.hpp:341
Evaluation log(const Evaluation &value)
Definition: MathToolbox.hpp:407
auto getValue(const Evaluation &val) -> decltype(MathToolbox< Evaluation >::value(val))
Definition: MathToolbox.hpp:330
Evaluation abs(const Evaluation &value)
Definition: MathToolbox.hpp:350