Skip to main content
Docs

Search guides and API endpoints, for example “Idempotency-Key” or “submit job”.

    Tools · Fluids & Thermodynamics

    PHREEQC Aqueous Speciation

    Aqueous speciation, pH, mineral saturation, redox, titrations, and mixing of water solutions with USGS PHREEQC.

    Updated October 1, 2026

    On this page

    Prices, workflows, and method papersOpen in the app

    PHREEQC (from the US Geological Survey) computes equilibrium in water: which species dissolved elements form, the solution's pH, ionic strength, and redox state, and whether minerals would dissolve or precipitate (saturation indices). It covers electrolyte and carbonate chemistry that gas-phase tools such as Cantera do not. The job runs PHREEQC 3.8.6 on CPU.

    Modes

    modeWhat it computes
    speciationThe species distribution, pH, and saturation indices of one solution, from its temperature and dissolved components (with optional pH, pe, or charge balance)
    titrationThe same, step by step, as a titrant is added
    mixingThe result of mixing two solutions in a given fraction

    Inputs

    One of:

    • a structured problem_spec for the chosen mode (the simplest);
    • a complete PHREEQC input deck as text (phreeqc_input), for anything the structured form doesn't cover;
    • an uploaded input file (problem).

    The thermodynamic database is phreeqc.dat by default, or one of wateq4f.dat, minteq.v4.dat, llnl.dat, and pitzer.dat (Pitzer for high-salinity brines). Uploading your own database isn't supported.

    Outputs

    • species.csv: the aqueous species and their concentrations and activities.
    • si.csv: mineral saturation indices (positive means supersaturated).
    • summary.json: pH, pe, ionic strength, and run details.

    Not covered

    Reactive transport and flow (PHAST) aren't available.

    Run it from the API

    Submit with Submit a job and the job_type below. Price it first with Estimate job reservation cost: submitting reserves that amount from your wallet, and the charge settles at the actual runtime.

    PHREEQC Aqueous Speciation phreeqc

    Job type
    phreeqc
    Hardware
    cpu (default)
    Typical runtime
    5 min on CPU

    Payload

    Provide exactly one of: phreeqc_input, problem, problem_spec.

    Payload fields
    FieldTypeDescription
    moderequiredstring

    One of: "speciation", "titration", "mixing"

    databasestring

    One of: "phreeqc.dat", "wateq4f.dat", "minteq.v4.dat", "llnl.dat", "pitzer.dat"

    phreeqc_inputstring

    Limits: min length 1

    problemfile_object
    problem.namestring

    Limits: min length 1

    problem.filenamestring

    Limits: min length 1

    problem.content_b64string

    Limits: min length 1

    problem.contentany
    problem.bytesany
    problem_specobject
    problem_spec.temperaturenumber
    problem_spec.pHnumber
    problem_spec.penumber
    problem_spec.densitynumber
    problem_spec.pressurenumber
    problem_spec.unitsstring

    Limits: min length 1

    problem_spec.charge_balanceboolean | string
    problem_spec.solutes[]object[]

    Limits: min items 1

    problem_spec.solutes.namerequiredstring

    Limits: min length 1

    problem_spec.solutes.amountrequirednumber
    problem_spec.solutes.unitsstring

    Limits: min length 1

    problem_spec.titrantobject
    problem_spec.titrant.namerequiredstring

    Limits: min length 1

    problem_spec.titrant.concentrationrequirednumber

    Limits: > 0

    problem_spec.titrant.unitsstring

    Limits: min length 1

    problem_spec.n_stepsinteger

    Limits: ≥ 1

    problem_spec.to_pHnumber
    problem_spec.solution_aobject
    problem_spec.solution_bobject
    problem_spec.fraction_anumber

    Limits: ≥ 0, ≤ 1

    File fields take {"name": "x.pdb", "content_b64": "…"} or a stored artifact, {"$artifact": {"id": "art-…", "port": "…"}}. Files are up to 25 MiB each.

    Example

    from cognichem_client import CogniChem
    
    client = CogniChem.from_env()  # reads COGNICHEM_API_KEY
    payload = {
        "mode": "speciation",
        "database": "phreeqc.dat",
        "problem_spec": {
            "temperature": 25,
            "pH": 7,
            "solutes": [{"name": "Na", "amount": 0.01}, {"name": "Cl", "amount": 0.01}],
        },
    }
    
    estimate = client.jobs.estimate(job_type="phreeqc", payload=payload, resource="cpu")
    print(f"Reserves ${estimate.cost:.2f}")
    
    job = client.jobs.submit(
        job_name="my-phreeqc-run",
        job_type="phreeqc",
        payload=payload,
        resource="cpu",
    )
    status = client.jobs.wait(job.process_id)
    if status.status == "completed":
        client.jobs.result(job.process_id, save_path=".")

    Sample data from the job catalog; long values are shortened here. Each job_name must be unique among your jobs.

    Workflow inputs

    None

    Workflow outputs

    • ArchiveZIP
    • TableCSV