Water and non-condensable gas

A miscible water and non-condensable gas (NCG) model is available in PorousFlow based on the persistent variable approach.

Available NCG's

Any of the gaseous fluids provided in the Fluid Properties module can be used in this equation of state.

Phase composition

Henry's law is used to calculate the mass fraction of the NCG in the water phases while Raoult's law is used to calculate the mass fraction of HO in the gas phase where is vapor pressure of water.

As with many reservoir simulators, it is assumed that the phases are in instantaneous equilibrium, meaning that dissolution of NCG into the water and evaporation of water vapor into the gas phase happens instantaneously.

If the amount of NCG present is not sufficient to saturate the water, then no gas phase will be formed, and the dissolved NCG mass fraction will be smaller than its equilibrium value. Similarly, if the amount of water vapor present is smaller than its equilibrium value in the gas phase, then no liquid phase can be formed.

If there is sufficient NCG present to saturate the water, then both liquid and gas phases will be present. In this case, the mass fraction of NCG dissolved in the water is given by its equilibrium value. Similarly, the mass fraction of water vapor in the gas phase will be given by its equilibrium value in this two phase region.

Thermophysical properties

Density

The density of the gas phase is calculated as the sum of the densities of each fluid component at their partial pressure (via Dalton's law).

No change to the water density is calculated for dissolved NCG components.

Viscosity

The viscosity of the gas phase is given by a weighted sum of the viscosities of each fluid component

The viscosity of the liquid phase is simply given by the viscosity of water - no contribution due to dissolved NCG is included.

Enthalpy

The enthalpy of the gas phase is calculated as a weighted sum of the enthalpies of each fluid component

The enthalpy of the liquid phase is also calculated as a weighted sum of the enthalpies of each individual component, but also includes a contribution due to the enthalpy of dissolution (a change in enthalpy due to dissolution of the NCG into the water phase)

where is the enthalpy of the gaseous NCG, and is the enthalpy of dissolution of NCG into the liquid. An expression for the enthalpy of dissolution is implemented following (Himmelblau, 1959)

where is the molar mass of the NCG component, and is the universal gas constant.

Implementation

Variables

This class requires pressure of the gas phase and the total mass fraction of NCG summed over all phases (see compositional flash for details) for isothermal simulations. For nonisothermal simulations, the temperature must also be provided as a nonlinear variable.

commentnote

These variables must be listed as PorousFlow variables in the PorousFlowDictator UserObject

In the isothermal case, two variables (gas porepressure and total NCG mass fraction) are required. The number of components in the PorousFlowDictator must be set equal to two.

[UserObjects]
  [dictator]
    type = PorousFlowDictator
    porous_flow_vars = 'pgas zi'
    number_fluid_phases = 2
    number_fluid_components = 2
  []
[]
(modules/porous_flow/test/tests/fluidstate/theis.i)

In the nonisothermal case, three variables (gas porepressure, total NCG mass fraction and temperature) are required. The number of components in the PorousFlowDictator is still two.

[UserObjects]
  [dictator]
    type = PorousFlowDictator
    porous_flow_vars = 'pgas zi temperature'
    number_fluid_phases = 2
    number_fluid_components = 2
  []
[]
(modules/porous_flow/test/tests/fluidstate/theis_nonisothermal.i)

UserObjects

This fluid state is implemented in the PorousFlowWaterNCG UserObject. This UserObject is a GeneralUserObject that contains methods that provide a complete thermophysical description of the model given pressure, temperature and total NCG mass fraction.

[UserObjects]
  [fs]
    type = PorousFlowWaterNCG
    water_fp = water
    gas_fp = co2
    capillary_pressure = pc
  []
[]
(modules/porous_flow/test/tests/fluidstate/theis.i)

Swapping NCG's is as simple as changing the gas_fp parameter in this UserObject!

Materials

The PorousFlowFluidState material provides all phase pressures, saturation, densities, viscosities etc, as well as all mass fractions of all fluid components in all fluid phases in a single material using the formulation provided in the PorousFlowWaterNCG UserObject.

For isothermal simulations, this material will look like

[Materials]
  [waterncg]
    type = PorousFlowFluidState
    gas_porepressure = pgas
    z = zi
    temperature_unit = Celsius
    capillary_pressure = pc
    fluid_state = fs
  []
[]
(modules/porous_flow/test/tests/fluidstate/theis.i)

For nonisothermal simulations, the temperature variable must also be supplied to ensure that all the derivatives with respect to the temperature variable are computed for the Jacobian.

[Materials]
  [waterncg]
    type = PorousFlowFluidState
    gas_porepressure = pgas
    z = zi
    temperature = temperature
    temperature_unit = Celsius
    capillary_pressure = pc
    fluid_state = fs
  []
[]
(modules/porous_flow/test/tests/fluidstate/theis_nonisothermal.i)

Initial condition

The nonlinear variable representing NCG is the total mass fraction of NCG summed over all phases. In some cases, it may be preferred to provide an initial NCG saturation, rather than total mass fraction. To allow an initial saturation to be specified, the PorousFlowFluidStateIC initial condition is provided. This initial condition calculates the total mass fraction of NCG summed over all phases for a given saturation.

[ICs]
  [z]
    type = PorousFlowFluidStateIC
    saturation = 0.5
    gas_porepressure = pgas
    temperature = 50
    variable = z
    fluid_state = fs
  []
[]
(modules/porous_flow/test/tests/fluidstate/waterncg_ic.i)

Example

1D Radial injection

Injection into a one dimensional radial reservoir is a useful test of this class, as it admits a similarity solution , where is the radial distance from the injection well, and is time. This similarity solution holds even when complicated physics such as mutual solubility is included.

An example of an isothermal 1D radial injection problem is included in the test suite with CO as the NCG.

# Two phase Theis problem: Flow from single source using WaterNCG fluidstate.
# Constant rate injection 2 kg/s
# 1D cylindrical mesh
# Initially, system has only a liquid phase, until enough gas is injected
# to form a gas phase, in which case the system becomes two phase.

[Mesh]
  type = GeneratedMesh
  dim = 1
  nx = 40
  xmax = 200
  bias_x = 1.05
  coord_type = RZ
  rz_coord_axis = Y
[]

[GlobalParams]
  PorousFlowDictator = dictator
  gravity = '0 0 0'
[]

[AuxVariables]
  [saturation_gas]
    order = CONSTANT
    family = MONOMIAL
  []
  [x1]
    order = CONSTANT
    family = MONOMIAL
  []
  [y0]
    order = CONSTANT
    family = MONOMIAL
  []
[]

[AuxKernels]
  [saturation_gas]
    type = PorousFlowPropertyAux
    variable = saturation_gas
    property = saturation
    phase = 1
    execute_on = timestep_end
  []
  [x1]
    type = PorousFlowPropertyAux
    variable = x1
    property = mass_fraction
    phase = 0
    fluid_component = 1
    execute_on = timestep_end
  []
  [y0]
    type = PorousFlowPropertyAux
    variable = y0
    property = mass_fraction
    phase = 1
    fluid_component = 0
    execute_on = timestep_end
  []
[]

[Variables]
  [pgas]
    initial_condition = 20e6
  []
  [zi]
    initial_condition = 0
  []
[]

[Kernels]
  [mass0]
    type = PorousFlowMassTimeDerivative
    fluid_component = 0
    variable = pgas
  []
  [flux0]
    type = PorousFlowAdvectiveFlux
    fluid_component = 0
    variable = pgas
  []
  [mass1]
    type = PorousFlowMassTimeDerivative
    fluid_component = 1
    variable = zi
  []
  [flux1]
    type = PorousFlowAdvectiveFlux
    fluid_component = 1
    variable = zi
  []
[]

[UserObjects]
  [dictator]
    type = PorousFlowDictator
    porous_flow_vars = 'pgas zi'
    number_fluid_phases = 2
    number_fluid_components = 2
  []
  [pc]
    type = PorousFlowCapillaryPressureConst
    pc = 0
  []
  [fs]
    type = PorousFlowWaterNCG
    water_fp = water
    gas_fp = co2
    capillary_pressure = pc
  []
[]

[FluidProperties]
  [co2]
    type = CO2FluidProperties
  []
  [water]
    type = Water97FluidProperties
  []
[]

[Materials]
  [temperature]
    type = PorousFlowTemperature
    temperature = 20
  []
  [waterncg]
    type = PorousFlowFluidState
    gas_porepressure = pgas
    z = zi
    temperature_unit = Celsius
    capillary_pressure = pc
    fluid_state = fs
  []
  [porosity]
    type = PorousFlowPorosityConst
    porosity = 0.2
  []
  [permeability]
    type = PorousFlowPermeabilityConst
    permeability = '1e-12 0 0 0 1e-12 0 0 0 1e-12'
  []
  [relperm_water]
    type = PorousFlowRelativePermeabilityCorey
    n = 2
    phase = 0
    s_res = 0.1
    sum_s_res = 0.1
  []
  [relperm_gas]
    type = PorousFlowRelativePermeabilityCorey
    n = 2
    phase = 1
  []
[]

[BCs]
  [rightwater]
    type = DirichletBC
    boundary = right
    value = 20e6
    variable = pgas
  []
[]

[DiracKernels]
  [source]
    type = PorousFlowSquarePulsePointSource
    point = '0 0 0'
    mass_flux = 2
    variable = zi
  []
[]

[Preconditioning]
  [smp]
    type = SMP
    full = true
    petsc_options = '-snes_converged_reason -ksp_diagonal_scale -ksp_diagonal_scale_fix -ksp_gmres_modifiedgramschmidt -snes_linesearch_monitor'
    petsc_options_iname = '-ksp_type -pc_type -sub_pc_type -sub_pc_factor_shift_type -pc_asm_overlap -snes_atol -snes_rtol -snes_max_it'
    petsc_options_value = 'gmres      asm      lu           NONZERO                   2               1E-8       1E-10 20'
  []
[]

[Executioner]
  type = Transient
  solve_type = NEWTON
  end_time = 2e2
  [TimeStepper]
    type = IterationAdaptiveDT
    dt = 10
    growth_factor = 2
  []
[]

[VectorPostprocessors]
  [line]
    type = NodalValueSampler
    sort_by = x
    variable = 'pgas zi'
    execute_on = 'timestep_end'
  []
[]

[Postprocessors]
  [pgas]
    type = PointValue
    point = '1 0 0'
    variable = pgas
  []
  [sgas]
    type = PointValue
    point = '1 0 0'
    variable = saturation_gas
  []
  [zi]
    type = PointValue
    point = '1 0 0'
    variable = zi
  []
  [massgas]
    type = PorousFlowFluidMass
    fluid_component = 1
  []
  [x1]
    type = PointValue
    point = '1 0 0'
    variable = x1
  []
  [y0]
    type = PointValue
    point = '1 0 0'
    variable = y0
  []
[]

[Outputs]
  print_linear_residuals = false
  perf_graph = true
  [csvout]
    type = CSV
    execute_on = timestep_end
    execute_vector_postprocessors_on = final
  []
[]
(modules/porous_flow/test/tests/fluidstate/theis.i)

Initially, all of the CO injected is dissolved in the resident water, as the amount of CO is less than the dissolved mass fraction at equilibrium. After a while, the water near the injection well becomes saturated with CO, and a gas phase forms. This gas phase then spreads radially as injection continues.

A comparison of the results expressed in terms of the similarity solution is presented in Figure 1 for both nonlinear variables for the case where is fixed (evaluated using Postprocessors), and also the case where is fixed (evaluated using a VectorPostprocessor).

Figure 1: Similarity solution for 1D radial injection example

An nonisothermal example of the above problem, where cold CO is injected into a warm aquifer, is also provided in the test suite.

# Two-phase nonisothermal Theis problem: Flow from single source using WaterNCG fluidstate.
# Constant rate injection 2 kg/s of cold gas into warm reservoir
# 1D cylindrical mesh
# Initially, system has only a liquid phase, until enough gas is injected
# to form a gas phase, in which case the system becomes two phase.

[Mesh]
  [mesh]
    type = GeneratedMeshGenerator
    dim = 1
    nx = 40
    xmin = 0.1
    xmax = 200
    bias_x = 1.05
  []
  coord_type = RZ
  rz_coord_axis = Y
[]

[GlobalParams]
  PorousFlowDictator = dictator
  gravity = '0 0 0'
[]

[AuxVariables]
  [saturation_gas]
    order = CONSTANT
    family = MONOMIAL
  []
  [x1]
    order = CONSTANT
    family = MONOMIAL
  []
  [y0]
    order = CONSTANT
    family = MONOMIAL
  []
[]

[AuxKernels]
  [saturation_gas]
    type = PorousFlowPropertyAux
    variable = saturation_gas
    property = saturation
    phase = 1
    execute_on = timestep_end
  []
  [x1]
    type = PorousFlowPropertyAux
    variable = x1
    property = mass_fraction
    phase = 0
    fluid_component = 1
    execute_on = timestep_end
  []
  [y0]
    type = PorousFlowPropertyAux
    variable = y0
    property = mass_fraction
    phase = 1
    fluid_component = 0
    execute_on = timestep_end
  []
[]

[Variables]
  [pgas]
    initial_condition = 20e6
  []
  [zi]
    initial_condition = 0
  []
  [temperature]
    initial_condition = 70
    scaling = 1e-4
  []
[]

[Kernels]
  [mass0]
    type = PorousFlowMassTimeDerivative
    fluid_component = 0
    variable = pgas
  []
  [flux0]
    type = PorousFlowAdvectiveFlux
    fluid_component = 0
    variable = pgas
  []
  [mass1]
    type = PorousFlowMassTimeDerivative
    fluid_component = 1
    variable = zi
  []
  [flux1]
    type = PorousFlowAdvectiveFlux
    fluid_component = 1
    variable = zi
  []
  [energy]
    type = PorousFlowEnergyTimeDerivative
    variable = temperature
  []
  [heatadv]
    type = PorousFlowHeatAdvection
    variable = temperature
  []
  [conduction]
    type = PorousFlowHeatConduction
    variable = temperature
  []
[]

[UserObjects]
  [dictator]
    type = PorousFlowDictator
    porous_flow_vars = 'pgas zi temperature'
    number_fluid_phases = 2
    number_fluid_components = 2
  []
  [pc]
    type = PorousFlowCapillaryPressureConst
    pc = 0
  []
  [fs]
    type = PorousFlowWaterNCG
    water_fp = water
    gas_fp = methane
    capillary_pressure = pc
  []
[]

[FluidProperties]
  [methane]
    type = MethaneFluidProperties
  []
  [water]
    type = Water97FluidProperties
  []
[]

[Materials]
  [temperature]
    type = PorousFlowTemperature
    temperature = temperature
  []
  [waterncg]
    type = PorousFlowFluidState
    gas_porepressure = pgas
    z = zi
    temperature = temperature
    temperature_unit = Celsius
    capillary_pressure = pc
    fluid_state = fs
  []
  [porosity]
    type = PorousFlowPorosityConst
    porosity = 0.2
  []
  [permeability]
    type = PorousFlowPermeabilityConst
    permeability = '1e-12 0 0 0 1e-12 0 0 0 1e-12'
  []
  [relperm_water]
    type = PorousFlowRelativePermeabilityCorey
    n = 2
    phase = 0
    s_res = 0.1
    sum_s_res = 0.1
  []
  [relperm_gas]
    type = PorousFlowRelativePermeabilityCorey
    n = 2
    phase = 1
  []
  [rockheat]
    type = PorousFlowMatrixInternalEnergy
    specific_heat_capacity = 1000
    density = 2500
  []
  [rock_thermal_conductivity]
    type = PorousFlowThermalConductivityIdeal
    dry_thermal_conductivity = '50 0 0  0 50 0  0 0 50'
  []
[]

[BCs]
  [cold_gas]
    type = DirichletBC
    boundary = left
    variable = temperature
    value = 20
  []
  [gas_injecton]
    type = PorousFlowSink
    boundary = left
    variable = zi
    flux_function = -0.159155
  []
  [rightwater]
    type = DirichletBC
    boundary = right
    value = 20e6
    variable = pgas
  []
  [righttemp]
    type = DirichletBC
    boundary = right
    value = 70
    variable = temperature
  []
[]

[Preconditioning]
  [smp]
    type = SMP
    full = true
    petsc_options_iname = '-ksp_type -pc_type -sub_pc_type -sub_pc_factor_shift_type -pc_asm_overlap'
    petsc_options_value = 'gmres      asm      lu           NONZERO                   2'
  []
[]

[Executioner]
  type = Transient
  solve_type = NEWTON
  end_time = 1e4
  nl_abs_tol = 1e-7
  nl_rel_tol = 1e-5
  [TimeStepper]
    type = IterationAdaptiveDT
    dt = 1
    growth_factor = 1.5
  []
[]

[Postprocessors]
  [pgas]
    type = PointValue
    point = '2 0 0'
    variable = pgas
  []
  [sgas]
    type = PointValue
    point = '2 0 0'
    variable = saturation_gas
  []
  [zi]
    type = PointValue
    point = '2 0 0'
    variable = zi
  []
  [temperature]
    type = PointValue
    point = '2 0 0'
    variable = temperature
  []
  [massgas]
    type = PorousFlowFluidMass
    fluid_component = 1
  []
  [x1]
    type = PointValue
    point = '2 0 0'
    variable = x1
  []
  [y0]
    type = PointValue
    point = '2 0 0'
    variable = y0
  []
[]

[Outputs]
  print_linear_residuals = false
  perf_graph = true
  csv = true
[]
(modules/porous_flow/test/tests/fluidstate/theis_nonisothermal.i)

References

  1. DM Himmelblau. Partial molar heats and entropies of solution for gases dissolved in water from the freezing to near the critical point. The Journal of Physical Chemistry, 63(11):1803–1808, 1959.[BibTeX]