Water Chemistry Engine
A reusable, scientifically grounded Python engine for characterizing, blending, treating, comparing, and eventually optimizing water for brewing, fermentation, and other validated uses.
The engine is intentionally independent of web frameworks, databases, graphical interfaces, and product-specific persistence. End-user applications consume this package from separate projects.
Project status
The 0.2 deterministic forward-calculator milestone is complete. The engine can resolve reported source-water chemistry, blend multiple characterized sources, apply supported mineral additions, calculate the resulting water, compare it with target/reference criteria, and return auditable contribution, instruction, and notice data.
Version 0.2 also establishes Python 3.11 as the compatibility baseline, with CI coverage on Python 3.11 through 3.14. Public APIs remain pre-1.0 and may evolve as real consumer applications exercise the engine.
Implemented in 0.2
- source-water and target/reference profile models;
- preservation of exact values, ranges, bounds,
ND, reported statistics, reporting context, source-document metadata, and chlorine/chloramine data; - explicit source-resolution policy, including opt-in exact-range midpoints;
- fixed multi-source blending with conservative unknown propagation;
- supported mineral-addition stoichiometry and deterministic treatment;
- source, blend, and final target/reference comparison;
- combined source/treatment ion-contribution reporting;
- structured preparation instructions;
- structured notices for assumptions, unresolved inputs, model limitations, and deferred target-pH calculation.
Planned after 0.2
- 0.3: supported consumer-facing Python API and integration examples;
- 0.4: curated target/reference profiles;
- 0.5–0.6: automatic and ranked treatment optimization;
- 0.7: reusable working-water pH if a defensible model is ready;
- 0.8: BeerJSON/FermentationJSON interchange, conformance work, and 1.0 hardening.
AI-assisted document ingestion, accounts, persistence, browser UI, and native application code belong to separate consumer applications rather than this repository.
Repository structure
water-chemistry-engine/
├── src/
│ └── water_chemistry_engine/
├── tests/
├── docs/
├── reference-data/
├── schemas/
├── scripts/
└── test-vectors/
src/water_chemistry_engine
The importable Python engine package, using the standard src/ layout. It owns
scientific calculations, domain models, validation, warnings/notices,
optimization as it is added, and structured calculation results.
External applications such as web, automation, Mechani-Brew, and future native clients can consume the engine while providing their own interfaces and persistence.
Installation
Water Chemistry Engine requires Python 3.11 or newer. Install the published package with uv or pip:
uv add water-chemistry-engine
or:
python -m pip install water-chemistry-engine
Version 0.2 exposes useful module-level APIs for calculations and domain models. These APIs remain pre-1.0 and may evolve as the supported consumer-facing API is formalized in milestone 0.3.
Quickstart
This example blends equal volumes of two already-resolved water states. Calcium therefore blends from 40 mg/L and 80 mg/L to 60 mg/L:
from fermunits import Q_
from water_chemistry_engine.blending import BlendSource, blend_waters
from water_chemistry_engine.chemical_state import (
AqueousChemicalState,
DerivedIonConcentration,
)
from water_chemistry_engine.ions import Ion
source_a = AqueousChemicalState(
concentrations=(DerivedIonConcentration.mg_per_liter(Ion.CALCIUM, 40.0),)
)
source_b = AqueousChemicalState(
concentrations=(DerivedIonConcentration.mg_per_liter(Ion.CALCIUM, 80.0),)
)
blend = blend_waters(
(
BlendSource("Source A", source_a, Q_(1.0, "liter")),
BlendSource("Source B", source_b, Q_(1.0, "liter")),
)
)
calcium = blend.state.concentration_for(Ion.CALCIUM)
assert calcium is not None
print(calcium)
Expected output:
60.0 milligram / liter
Reported source-water values should normally be passed through the engine's explicit source-resolution workflow before blending. The example starts from resolved states to keep the first installed-package example focused.
Development stack
- Python 3.11+ (CI tests 3.11–3.14; 3.11 is the compatibility baseline)
- uv
- FermUnits
- pytest and Hypothesis
- Ruff
- mypy
- GitHub Actions
Development
Install uv, then run from the repository root. The checked-in
.python-version selects the Python 3.11 compatibility baseline:
uv sync --dev
uv run pytest
The full CI gate tests Python 3.11, 3.12, 3.13, and 3.14. It also checks the lockfile, formatting, linting, strict typing against Python 3.11 semantics, and builds the engine distribution.
Documentation
Primary project documents are stored under docs/:
WATER_CHEM_DESIGN.md— scientific and architectural design;WATER_CHEM_REFERENCES.md— source and reference register;ROADMAP.md— active engine release path;PROJECT_STRUCTURE.md— repository/package boundaries;reviews/— point-in-time external review records.
Release history is summarized in CHANGELOG.md.
License
This project is licensed under the Mozilla Public License 2.0.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file water_chemistry_engine-0.2.0.tar.gz.
File metadata
- Download URL: water_chemistry_engine-0.2.0.tar.gz
- Upload date:
- Size: 38.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
650acc0a21bde92d140b21c9f87208dcb3b82547953294542bffeb0fc955e7f1
|
|
| MD5 |
91a7efa31f91b97e27b225ac6d592aab
|
|
| BLAKE2b-256 |
87caf92a79fb2f6cf5b4c12871329d8c32a42bd5474e2aa96560307c79885fcf
|
Provenance
The following attestation bundles were made for water_chemistry_engine-0.2.0.tar.gz:
Publisher:
release.yml on GregRR/water-chemistry-engine
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
water_chemistry_engine-0.2.0.tar.gz -
Subject digest:
650acc0a21bde92d140b21c9f87208dcb3b82547953294542bffeb0fc955e7f1 - Sigstore transparency entry: 2659239394
- Sigstore integration time:
-
Permalink:
GregRR/water-chemistry-engine@96293c67e4bc1c930075312169f9c812c2b40422 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/GregRR
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@96293c67e4bc1c930075312169f9c812c2b40422 -
Trigger Event:
push
-
Statement type:
File details
Details for the file water_chemistry_engine-0.2.0-py3-none-any.whl.
File metadata
- Download URL: water_chemistry_engine-0.2.0-py3-none-any.whl
- Upload date:
- Size: 53.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4dfb0558e69c83de968fb95eeb42810be138ad29c0346c9934181c56ebd66ca1
|
|
| MD5 |
a4875983dad30005e84a2a4110866d18
|
|
| BLAKE2b-256 |
bf5727e0c91ed5a728ce191bb291462148314c0d5af6b819689c48b9c20a951c
|
Provenance
The following attestation bundles were made for water_chemistry_engine-0.2.0-py3-none-any.whl:
Publisher:
release.yml on GregRR/water-chemistry-engine
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
water_chemistry_engine-0.2.0-py3-none-any.whl -
Subject digest:
4dfb0558e69c83de968fb95eeb42810be138ad29c0346c9934181c56ebd66ca1 - Sigstore transparency entry: 2659239740
- Sigstore integration time:
-
Permalink:
GregRR/water-chemistry-engine@96293c67e4bc1c930075312169f9c812c2b40422 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/GregRR
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@96293c67e4bc1c930075312169f9c812c2b40422 -
Trigger Event:
push
-
Statement type: