Real
PorousFlowFluidStateFlash::vaporMassFraction(std::vector<Real> & zi, std::vector<Real> & Ki) const
{
  // Check that the sizes of the mass fractions and equilibrium constant vectors are correct
  if (Ki.size() != zi.size() + 1)
    mooseError("The number of mass fractions or equilibrium components passed to rachfordRice is "
               "not correct");
  Real v;

  // If there are only two components, an analytical solution is possible
  if (Ki.size() == 2)
    v = vaporMassFraction(zi[0], Ki[0], Ki[1]);
  else
  {
    // More than two components - solve the Rachford-Rice equation using
    // Newton-Raphson method
    // Initial guess for vapor mass fraction
    Real v0 = 0.5;
    unsigned int iter = 0;

    while (std::abs(rachfordRice(v0, zi, Ki)) > _nr_tol)
    {
      v0 = v0 - rachfordRice(v0, zi, Ki) / rachfordRiceDeriv(v0, zi, Ki);
      iter++;

      if (iter > _nr_max_its)
        break;
    }
    v = v0;
  }
  return v;
}
Exemple #2
0
void
PorousFlowWaterNCG::saturationTwoPhase(Real pressure,
                                       Real temperature,
                                       Real Z,
                                       std::vector<FluidStateProperties> & fsp) const
{
  FluidStateProperties & liquid = fsp[_aqueous_phase_number];
  FluidStateProperties & gas = fsp[_gas_phase_number];

  // Mass fractions
  const Real Xncg = liquid.mass_fraction[_gas_fluid_component];
  const Real dXncg_dp = liquid.dmass_fraction_dp[_gas_fluid_component];
  const Real dXncg_dT = liquid.dmass_fraction_dT[_gas_fluid_component];

  const Real Yncg = gas.mass_fraction[_gas_fluid_component];
  const Real dYncg_dp = gas.dmass_fraction_dp[_gas_fluid_component];
  const Real dYncg_dT = gas.dmass_fraction_dT[_gas_fluid_component];

  // Calculate the vapor mass fraction
  const Real K0 = Yncg / Xncg;
  const Real K1 = (1.0 - Yncg) / (1.0 - Xncg);
  const Real vapor_mass_fraction = vaporMassFraction(Z, K0, K1);

  // Liquid density is a function of gas saturation through the capillary pressure
  // curve, so approximate liquid pressure as gas pressure
  const Real liquid_pressure = pressure;

  Real liquid_density, liquid_ddensity_dp, liquid_ddensity_dT;
  _water_fp.rho_from_p_T(
      liquid_pressure, temperature, liquid_density, liquid_ddensity_dp, liquid_ddensity_dT);

  // The gas saturation in the two phase case
  gas.saturation = vapor_mass_fraction * liquid_density /
                   (gas.density + vapor_mass_fraction * (liquid_density - gas.density));

  const Real dv_dZ = (K1 - K0) / ((K0 - 1.0) * (K1 - 1.0));
  const Real denominator = (gas.density + vapor_mass_fraction * (liquid_density - gas.density)) *
                           (gas.density + vapor_mass_fraction * (liquid_density - gas.density));

  const Real ds_dZ = gas.density * liquid_density * dv_dZ / denominator;

  const Real dK0_dp = (Xncg * dYncg_dp - Yncg * dXncg_dp) / Xncg / Xncg;
  const Real dK0_dT = (Xncg * dYncg_dT - Yncg * dXncg_dT) / Xncg / Xncg;

  const Real dK1_dp =
      ((1.0 - Yncg) * dXncg_dp - (1.0 - Xncg) * dYncg_dp) / (1.0 - Xncg) / (1.0 - Xncg);
  const Real dK1_dT =
      ((1.0 - Yncg) * dXncg_dT - (1.0 - Xncg) * dYncg_dT) / (1.0 - Xncg) / (1.0 - Xncg);

  const Real dv_dp =
      Z * dK1_dp / (K1 - 1.0) / (K1 - 1.0) + (1.0 - Z) * dK0_dp / (K0 - 1.0) / (K0 - 1.0);

  Real ds_dp = gas.density * liquid_density * dv_dp +
               vapor_mass_fraction * (1.0 - vapor_mass_fraction) *
                   (gas.density * liquid_ddensity_dp - gas.ddensity_dp * liquid_density);
  ds_dp /= denominator;

  const Real dv_dT =
      Z * dK1_dT / (K1 - 1.0) / (K1 - 1.0) + (1.0 - Z) * dK0_dT / (K0 - 1.0) / (K0 - 1.0);

  Real ds_dT = gas.density * liquid_density * dv_dT +
               vapor_mass_fraction * (1.0 - vapor_mass_fraction) *
                   (gas.density * liquid_ddensity_dT - gas.ddensity_dT * liquid_density);
  ds_dT /= denominator;

  gas.dsaturation_dp = ds_dp;
  gas.dsaturation_dT = ds_dT;
  gas.dsaturation_dZ = ds_dZ;
}