Skip to content

Gases

A Gas is a PHREEQC GAS_PHASE that stays in the engine, like a Solution. You create it on a PhreeqPython instance with add_gas, then query pressure, volume, and composition, or interact it with a solution. To hold a single gas at a fixed partial pressure (for example CO2(g) at 10^-3.5 atm), use equalize / saturate instead of a Gas object.

PHREEQC has two kinds of gas phase. They cannot be combined:

  • Fixed pressure: total pressure stays constant; volume can change (an open headspace, or a piston).
  • Fixed volume: volume stays constant; pressure can change (a closed bottle).

See the GAS_PHASE keyword in the PHREEQC manual for the full identifier list.

You can run these examples

Click Run (or Ctrl+Enter), or Run all to execute every editor in order. The first run loads Pyodide and can take a few seconds. Editors on this page share a session.

Creating a gas

The components dictionary lists gas names from the database (CO2(g), O2(g), N2(g), CH4(g), H2O(g), …). The values are initial partial pressures in atm. PHREEQC converts those, with volume and temperature, to moles (n = PV/RT for an ideal gas). Include gases with partial pressure 0 if they may enter the phase later.

Default: pressure=1 atm, volume=1 L, fixed_pressure=True.

Fixed pressure

Total pressure is held at a fixed pressure. After reaction with a solution, the volume adjusts so that the pressure stays constant.

Editor (session: gases)Run
from phreeqpython import PhreeqPython

pp = PhreeqPython()
air = pp.add_gas(
    {'N2(g)': 0.78, 'O2(g)': 0.21, 'CO2(g)': 0.0004},
    pressure=1.0,
    volume=1.0,
    fixed_pressure=True,
)
print('P', round(air.pressure, 4), 'atm, V', round(air.volume, 4), 'L')
print('partial pressures', {k: round(v, 4) for k, v in air.partial_pressures.items()})
OutputClear

Fixed volume

Volume is held at a fixed volume. After reaction, the pressure (and partial pressures) can change.

You can only pass equilibrate_with for a fixed-volume gas. PHREEQC then calculates the initial gas composition from that solution; the numbers in components are ignored except as a list of which gases may be present.

Editor (session: gases)Run
headspace = pp.add_gas(
    {'CH4(g)': 0.5, 'N2(g)': 0.5},
    pressure=1.0,
    volume=1.0,
    fixed_pressure=False,
    fixed_volume=True,
)
print('P', round(headspace.pressure, 4), 'atm, V', round(headspace.volume, 4), 'L')
print('moles', {k: round(v, 4) for k, v in headspace.components.items()})

sol = pp.add_solution({}).equalize(['Calcite', 'CO2(g)'], [0, -1.5])
from_sol = pp.add_gas(
    {'CO2(g)': 0, 'N2(g)': 0, 'H2O(g)': 0},
    volume=1.0,
    fixed_pressure=False,
    fixed_volume=True,
    equilibrate_with=sol,
)
print('equilibrated P_CO2', round(from_sol.partial_pressures.get('CO2(g)', 0), 4))
OutputClear

add_gas raises ValueError if both fixed_pressure and fixed_volume are true, or if equilibrate_with is set on a fixed-pressure gas.

Interact

solution.interact(gas) brings the solution and gas to equilibrium and saves both back to the engine. The Python objects are updated in place.

The example is 1 L of air over 1 kg of pure water at 25 °C. Dissolved oxygen after interact is the air-saturated value at that temperature.

Editor (session: gases)Run
air = pp.add_gas(
    {'N2(g)': 0.78, 'O2(g)': 0.21, 'CO2(g)': 0.0004},
    pressure=1.0,
    volume=1.0,
    fixed_pressure=True,
)
water = pp.add_solution({'temp': 25})
print('O2 before interact', round(water.total('O2', 'mg'), 3), 'mg/kgw')
water.interact(air)
print('O2 after interact ', round(water.total('O2', 'mg'), 2), 'mg/kgw')
print('O2 after interact ', round(water.total('O2', 'mmol'), 3), 'mmol')
print('P', round(air.pressure, 4), 'atm, V', round(air.volume, 4), 'L')
OutputClear

Use copy() when you need an independent gas for another step, and forget() when you are done (same idea as for solutions).

Composition and pressures

After each calculation you can read:

Editor (session: gases)Run
print('total moles', round(air.total_moles, 4))
print('components', {k: round(v, 5) for k, v in air.components.items()})
print('fractions', {k: round(v, 4) for k, v in air.fractions.items()})
print('partial P', {k: round(v, 4) for k, v in air.partial_pressures.items()})
print('dry fractions', {k: round(v, 4) for k, v in air.dry_fractions.items()})
OutputClear

Futher examples: gas solubilities and fixed-pressure vs fixed-volume after organic-matter reaction. See the API reference for Gas for every property.