Documentation

Methodology

How Crysalt turns a brine and a set of conditions into a scale prediction: the activity model, the solubility products, the equilibrium solver, the gas phase, where the parameters come from, and how it is validated. The physics — and the limits — are stated in the open.

Activity coefficients (γ)

Real oilfield brines are far from ideal, so every concentration is corrected by an activity coefficient γ (activity a = γ·m). Two models are available:

  • Ideal (γ ≡ 1) — the default; fast, and adequate only for dilute systems.
  • Pitzer — the Harvie-Møller-Weare ion-interaction model, required for the high-salinity brines typical of production. It computes the binary (β⁰, β¹, β², Cφ), same-sign (θ), triplet (ψ) and neutral-ion (λ) interaction terms over the full ionic strength.

Activity coefficients are lagged in an outer loop and folded into each reaction's stoichiometric constant, so the Newton solve itself never changes:

Kstoic = Ktherm · ∏c γcσc σc = the species' stoichiometric coefficient. The loop re-evaluates γ at the new speciation and re-solves until γ stops changing (tolerance 10⁻⁹, ≤ 50 passes). The ideal model returns γ ≡ 1 and converges in a single pass.

The activity model sees the full speciation — the reactive ions and the inert background (e.g. NaCl), which carries most of the ionic strength I = ½·Σ mᵢzᵢ². Saturation ratios use activities too (γ·m), not bare molality.

Equilibrium constants & solubility products

Each reaction's thermodynamic constant is computed from five fitted coefficients as a function of temperature (T in kelvin):

Ktherm(T) = exp( K₁/T + K₂ + K₃·ln T + K₄·T + K₅/T² )

Mineral solubility products are then pressure-corrected with a molar-volume term, so a prediction at reservoir pressure uses the right Ksp:

ln[ K(P) / K(Pr) ] = −(ΔV°/RT)·(P − Pr) + (Δκ°/2RT)·(P − PrR = 83.145 cm³·bar/(mol·K), reference Pr = 1 bar. ΔV° and Δκ° per mineral are fitted to PHREEQC's Ksp(P) at 25 °C and reproduce it to < 1%.

This applies to the sulfate, carbonate and halite scales (barite, celestite, gypsum, anhydrite, calcite + aragonite/vaterite, halite). The ΔV° terms are held constant in temperature, so combined high-T / high-P accuracy is approximate; siderite and the sulfides (FeS, ZnS, PbS) carry no pressure correction (their molar-volume data is sparse).

The equilibrium solver

Crysalt solves the coupled mass-action and mass-balance equations with a Newton-Raphson method. It partitions the system into a compact basis (after Bethke):

BasisRole
Aᵢ — independent speciesThe free unknowns of the Newton solve (ranked by molality).
Aⱼ — dependent speciesDerived from Aᵢ by mass action — not unknowns.
Aₖ — solidsOne mass-balance row each; their precipitated moles are unknowns.
A𝓌 — waterThe solvent mass is an unknown (≈ 55.5 mol/kg).
Aₘ — gas bufferA fixed-fugacity constituent (open system) — an input, not an unknown.

Each Newton step builds the residual (mass imbalance) and the Jacobian, then solves the dense linear system with an in-house Gaussian-elimination solver (partial pivoting, allocation-free — the engine carries no external numerical dependencies). It iterates until the scaled residual falls below tolerance; the result reports whether it converged (and if not — singular, non-finite, or iteration/basis limits — it says so, and a warning is surfaced). Inert background ions are not Newton unknowns but still contribute to the ionic strength the activity model sees.

On top of that, scale prediction runs a precipitate↔dissolve loop: it precipitates the most supersaturated solid, re-solves, and repeats — dissolving any solid that becomes undersaturated — until the solid amounts stabilise. Before solving, the brine is charge-balanced (Σ m·z = 0) by topping up Na⁺ or Cl⁻; concentrations entered in mg/L are converted to molality on a per-litre-of-brine basis (water density 0.997 kg/L).

Gas phase (open-system partitioning)

The brine can be opened to a co-existing gas of known composition. Each dissolved gas is pinned by Henry's law to its fugacity, and pH, speciation and the dependent scales respond — the mechanism behind gas exsolution as a brine depressurises from reservoir to surface:

mᵢ = KH(T) · fᵢ , with fᵢ = φᵢ · yᵢ · P yᵢ = mole fraction in the gas, P = total pressure, φᵢ = fugacity coefficient. Implemented as Bethke's fixed-fugacity constituent (Aₘ). CO₂ drives carbonate (CaCO₃); H₂S drives sulfides (FeS/ZnS/PbS) and pH; CH₄ is scale-inert but enters the mixture fugacity.

At elevated pressure two corrections switch on (both no-ops at 1 bar): a Peng-Robinson equation-of-state fugacity coefficient φ over the whole CO₂/H₂S/CH₄ mixture (van der Waals mixing with binary interaction parameters), and a Krichevsky-Kasarnovsky / Poynting term mᵢ = KH·exp(−v̄ᵢ(P−1)/RT)·fᵢ for the partial molar volume of the dissolved gas.

Where the parameters come from

The Pitzer parameters are code-defined and self-describing — each carries its source and its temperature function — and are layered by priority (lowest number wins when several define a pair, so primary sources supersede the baseline compilation):

SourceCoversPriority
Monnin (1999)Ba/Sr–SO₄ ion-pair framework (zeroes the free-ion binaries)5
Appelo (2015) / PHREEQC pitzer.datSulfate-system binaries (Ca/Na/K/Mg–SO₄) + θ(Cl,SO₄)10
Christov & Møller (2004)Acid–base system (H-Na-K-OH-Cl-HSO₄-SO₄), 0–250 °C20
Kaasa (1998) + primary literatureBaseline compilation (transcribed, per-pair provenance)100

Each coefficient is evaluated with the temperature function its source used — a 6-term Kaasa form (Tr = 298.15 K), the 8-term Christov & Møller form, the Greenberg-Møller high-T CaSO₄ form, or a constant — so a parameter can never be evaluated with the wrong equation.

Validation

Crysalt is validated against published experimental data and an independent reference code (PHREEQC, USGS, run on its own pitzer.dat). Agreement with a separately-fitted implementation is a genuine cross-check — and results are reported against experiment too, so where the two codes differ it is not assumed Crysalt is the one that is off. Headline results:

PropertyAgreementReference
Activity coefficients γ± (NaCl, Na₂SO₄, CaCl₂)< 1% vs experiment (0.1–3 m)Robinson & Stokes 1959
Mineral log Ksp (barite, celestite, gypsum, anhydrite)within ~0.1 log of experiment (barite beats PHREEQC)Blount 1977 et al.
Barite salting-in factor (1 m / 0.01 m NaCl)2.5% vs PHREEQC; both ≈ experiment (~5×)Blount 1977
CaSO₄ solubility vs T (anhydrite, ≥ 60 °C)< 1% vs PHREEQC; retrograde shape reproducedMøller 1988
Carbonate pK₁ / pK₂; CaCO₃ & siderite log KsppK₂ exact; Ksp within ~0.02 log of experimentPlummer & Busenberg 1982
Dissolved CO₂/H₂S/CH₄ & pH vs partial pressuregases ~0.5%, pH ±0.01 vs PHREEQCPHREEQC databases
Mixture fugacity coefficients φ< 10⁻³ vs a reference Peng-Robinson portPeng & Robinson 1976

Every number is reproducible from the repository's benchmark tests and PHREEQC cross-check scripts — the full tables, per-system, are in VALIDATION.md.

Scope — what v1 models, and what it doesn't

Crysalt is deliberately focused on oilfield scale rather than general aqueous chemistry. The boundaries are stated openly:

StatusCapability
Now Aqueous equilibrium & precipitation for the supported scales; temperature-dependent sulfate/carbonate data; pressure-dependent Ksp(T,P); brine mixing; reservoir→surface profiles; gas–water partitioning of CO₂/H₂S/CH₄ (Henry's law at a fixed gas composition, with Peng-Robinson mixture fugacity).
Deferred Full vapour–liquid flash (water vapour and a predicted gas split, rather than a fixed gas composition supplied as input); precipitation kinetics; scale inhibitors.
Out of scope Redox speciation (oxidation states are fixed); a broad general-chemistry ion set; silica and organic scales.

Known limitations

  • Pressure — Ksp(P) is fitted at 25 °C with temperature-constant ΔV°, so combined high-T/high-P is approximate; γ(P) is not modelled, bounding accuracy to ~10% at 1 kbar. Siderite and the sulfides get no pressure correction.
  • Sulfate at high ionic strength — the shipped Kaasa Na₂SO₄ parameters over-predict salting-in above ~1 m. The engine matches experiment to < 1% with canonical parameters, so this is a data-quality limit, not an engine error.
  • Missing interaction parameters — Fe²⁺, Zn²⁺, Pb²⁺ and the neutral gases (CO₂, H₂S, CH₄) have no Pitzer/λ terms in the shipped set, so they default to γ = 1 (no dissolved-gas salting-out, and sulfide/siderite scaling is reliable only at low–moderate ionic strength).
  • Na–HCO₃ activity — the one open carbonate item; it leaves a bounded ~1–6% residual in calcite-vs-temperature (the Ksp itself matches experiment).

See the minerals & species reference for the supported set.

An unhandled error has occurred. Reload 🗙