chemthermo 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. chemthermo-0.4.0/CHANGELOG.md +172 -0
  2. chemthermo-0.4.0/LICENSE +21 -0
  3. chemthermo-0.4.0/MANIFEST.in +11 -0
  4. chemthermo-0.4.0/PKG-INFO +196 -0
  5. chemthermo-0.4.0/README.md +154 -0
  6. chemthermo-0.4.0/pyproject.toml +103 -0
  7. chemthermo-0.4.0/setup.cfg +4 -0
  8. chemthermo-0.4.0/src/chemthermo/__init__.py +96 -0
  9. chemthermo-0.4.0/src/chemthermo/__main__.py +8 -0
  10. chemthermo-0.4.0/src/chemthermo/_eos_memo.py +214 -0
  11. chemthermo-0.4.0/src/chemthermo/bench/__init__.py +313 -0
  12. chemthermo-0.4.0/src/chemthermo/bench/__main__.py +10 -0
  13. chemthermo-0.4.0/src/chemthermo/bench/_cases.py +614 -0
  14. chemthermo-0.4.0/src/chemthermo/bench/_record.py +187 -0
  15. chemthermo-0.4.0/src/chemthermo/bench/robustness.py +2101 -0
  16. chemthermo-0.4.0/src/chemthermo/citations.py +59 -0
  17. chemthermo-0.4.0/src/chemthermo/cli.py +509 -0
  18. chemthermo-0.4.0/src/chemthermo/core/__init__.py +7 -0
  19. chemthermo-0.4.0/src/chemthermo/core/component.py +197 -0
  20. chemthermo-0.4.0/src/chemthermo/core/composition.py +48 -0
  21. chemthermo-0.4.0/src/chemthermo/core/mixture.py +66 -0
  22. chemthermo-0.4.0/src/chemthermo/data/__init__.py +88 -0
  23. chemthermo-0.4.0/src/chemthermo/data/components.json +3449 -0
  24. chemthermo-0.4.0/src/chemthermo/data/references.bib +6 -0
  25. chemthermo-0.4.0/src/chemthermo/data/schema.py +9 -0
  26. chemthermo-0.4.0/src/chemthermo/eos/__init__.py +13 -0
  27. chemthermo-0.4.0/src/chemthermo/eos/_pcsaft_association.py +664 -0
  28. chemthermo-0.4.0/src/chemthermo/eos/_pcsaft_density.py +653 -0
  29. chemthermo-0.4.0/src/chemthermo/eos/api.py +29 -0
  30. chemthermo-0.4.0/src/chemthermo/eos/pcsaft.py +1456 -0
  31. chemthermo-0.4.0/src/chemthermo/eos/registry.py +44 -0
  32. chemthermo-0.4.0/src/chemthermo/exceptions.py +25 -0
  33. chemthermo-0.4.0/src/chemthermo/flash/__init__.py +7 -0
  34. chemthermo-0.4.0/src/chemthermo/flash/_assemble.py +129 -0
  35. chemthermo-0.4.0/src/chemthermo/flash/_common.py +327 -0
  36. chemthermo-0.4.0/src/chemthermo/flash/_detect.py +1768 -0
  37. chemthermo-0.4.0/src/chemthermo/flash/_legacy.py +143 -0
  38. chemthermo-0.4.0/src/chemthermo/flash/_log_space.py +698 -0
  39. chemthermo-0.4.0/src/chemthermo/flash/_multiphase.py +1404 -0
  40. chemthermo-0.4.0/src/chemthermo/flash/_multiphase_log_space.py +406 -0
  41. chemthermo-0.4.0/src/chemthermo/flash/_multiphase_rr.py +433 -0
  42. chemthermo-0.4.0/src/chemthermo/flash/_second_order.py +263 -0
  43. chemthermo-0.4.0/src/chemthermo/flash/_split.py +764 -0
  44. chemthermo-0.4.0/src/chemthermo/flash/_verify.py +310 -0
  45. chemthermo-0.4.0/src/chemthermo/flash/api.py +5 -0
  46. chemthermo-0.4.0/src/chemthermo/flash/results.py +99 -0
  47. chemthermo-0.4.0/src/chemthermo/flash/settings.py +154 -0
  48. chemthermo-0.4.0/src/chemthermo/flash/tp.py +519 -0
  49. chemthermo-0.4.0/src/chemthermo/models/__init__.py +7 -0
  50. chemthermo-0.4.0/src/chemthermo/models/_antoine.py +125 -0
  51. chemthermo-0.4.0/src/chemthermo/models/_kij.py +115 -0
  52. chemthermo-0.4.0/src/chemthermo/models/base.py +216 -0
  53. chemthermo-0.4.0/src/chemthermo/models/nrtl.py +148 -0
  54. chemthermo-0.4.0/src/chemthermo/models/peng_robinson.py +459 -0
  55. chemthermo-0.4.0/src/chemthermo/parameters/__init__.py +21 -0
  56. chemthermo-0.4.0/src/chemthermo/parameters/activity.py +23 -0
  57. chemthermo-0.4.0/src/chemthermo/parameters/data/activity/nrtl.json +32 -0
  58. chemthermo-0.4.0/src/chemthermo/parameters/data/eos/pcsaft.json +189 -0
  59. chemthermo-0.4.0/src/chemthermo/parameters/nrtl.py +163 -0
  60. chemthermo-0.4.0/src/chemthermo/parameters/pcsaft.py +458 -0
  61. chemthermo-0.4.0/src/chemthermo/phase_boundary.py +479 -0
  62. chemthermo-0.4.0/src/chemthermo/py.typed +0 -0
  63. chemthermo-0.4.0/src/chemthermo/schemas.py +93 -0
  64. chemthermo-0.4.0/src/chemthermo/stability/__init__.py +7 -0
  65. chemthermo-0.4.0/src/chemthermo/stability/_evaluator.py +1087 -0
  66. chemthermo-0.4.0/src/chemthermo/stability/results.py +224 -0
  67. chemthermo-0.4.0/src/chemthermo/stability/settings.py +73 -0
  68. chemthermo-0.4.0/src/chemthermo/stability/tp.py +1165 -0
  69. chemthermo-0.4.0/src/chemthermo/units.py +10 -0
  70. chemthermo-0.4.0/src/chemthermo/validation.py +72 -0
  71. chemthermo-0.4.0/src/chemthermo/vle.py +11 -0
  72. chemthermo-0.4.0/src/chemthermo.egg-info/PKG-INFO +196 -0
  73. chemthermo-0.4.0/src/chemthermo.egg-info/SOURCES.txt +75 -0
  74. chemthermo-0.4.0/src/chemthermo.egg-info/dependency_links.txt +1 -0
  75. chemthermo-0.4.0/src/chemthermo.egg-info/entry_points.txt +2 -0
  76. chemthermo-0.4.0/src/chemthermo.egg-info/requires.txt +16 -0
  77. chemthermo-0.4.0/src/chemthermo.egg-info/top_level.txt +1 -0
@@ -0,0 +1,172 @@
1
+ # Changelog
2
+
3
+ Versions follow PEP 440 and are tagged `v<version>` on one tested commit
4
+ (policy: `.agents/brain/adr/0031-versioned-releases.md`). Releases up to
5
+ 0.3.0b1 were GitHub-only; from 0.4.0 the owner also publishes to PyPI by hand
6
+ (ADR-0038).
7
+
8
+ ## 0.4.0 (2026-09-25) - first PyPI release (Beta)
9
+
10
+ The first release published to PyPI (`pip install chemthermo`), with a short,
11
+ honest README, the reference material moved to `docs/`, and packaging checked
12
+ for PyPI. Beta: validated against independent implementations on macOS arm64
13
+ and Linux x86_64, but the public API may still change before 1.0.
14
+
15
+ ### Breaking
16
+ - **`chemthermo.vlle` is removed** (deprecated since ADR-0013; ADR-0037).
17
+ `import chemthermo.vlle` raises `ModuleNotFoundError`; three-phase
18
+ equilibrium is found by `flash_tp` itself (`FlashSettings(max_phases=3)`,
19
+ the default). `flash_mode="vlle"` still raises `ModelError` with that pointer.
20
+
21
+ ### Packaging
22
+ - PyPI metadata (summary, classifiers, URLs, keywords), `py.typed`, an sdist
23
+ that carries the library only (tests are excluded: some of their fixtures
24
+ are not redistributable). Supported and CI-tested on Python 3.11, 3.12 and
25
+ 3.13; CI also runs `twine check --strict`.
26
+
27
+ ### Documentation
28
+ - README rewritten as a summary: quick start, a capability table naming what
29
+ each claim was checked against, and the limits. The previous detail is in
30
+ `docs/` (installation, flash, stability, PC-SAFT, CLI, extending,
31
+ benchmarks). `CONTRIBUTING.md` added.
32
+
33
+ ### Added
34
+ - PC-SAFT **association** temperature derivative: `residual_helmholtz_temperature_derivative`
35
+ and `residual_properties` now work for water, alcohols and their mixtures
36
+ (they raised `ModelError` in 0.3.0b1). Checked against FeOs residual entropy
37
+ and enthalpy (2.1e-15 with matched universal constants). ADR-0034 amendment,
38
+ ledger Case P-20.
39
+
40
+ ### Fixed
41
+ - `flash_tp` (phi-phi): a split whose two phases are identical (the trivial
42
+ solution) no longer counts as converged, so the stability-seed ladder runs.
43
+ Around the Mw 53000 polyethylene ladder state, 29 of 135 neighbouring
44
+ pressures (+-64 ULP) refused; now none does. The full 2505-state
45
+ robustness map is unchanged field for field. ADR-0036.
46
+
47
+ ### Changed
48
+ - `stability_tp`: on a `tpd` tie (within 1e-12) the reported minimizing trial
49
+ is one converged at least 1000x better, when one exists; flagged by
50
+ `diagnostics["minimizing_trial_tie_break"] = "residual"`. Changes only such
51
+ ties (none on any captured state). ADR-0035.
52
+
53
+ ### Validation for this release
54
+ - Full 2505-state robustness map at `761fd57` (Linux): 2500 converge, 5
55
+ by-design gamma-phi refusals, 0 invariant violations; identical state by
56
+ state to the earlier macOS record at `f852726` (`benchmarks/robustness_761fd57.*`).
57
+ - Default suite on Python 3.11 / 3.12 / 3.13 (numpy 2.4.6 and 2.5.3), and
58
+ with the validation extras (teqp, FeOs, thermo) on 3.11.
59
+
60
+ ## 0.3.0b1 (2026-09-25) - prerelease
61
+
62
+ The CLI reaches the equilibrium work, PC-SAFT gains residual caloric
63
+ properties, and the test suite is green on Linux for the first time. A
64
+ prerelease because the CLI contract (ADR-0033) and the two PC-SAFT methods
65
+ (ADR-0034) are new. Validation now spans two platforms (macOS arm64 inherited
66
+ at 0.2.0b1; Linux x86_64 on GitHub Actions and a cloud session for this
67
+ release), but this release's new code was exercised on Linux only.
68
+ There is no 0.2.0b2; its planned content (the cross-platform guards) is here.
69
+
70
+ ### Compatibility
71
+ - Library: additive only (two new `PCSAFTEOS` methods). No existing number
72
+ moved: the new derivative is a separate function, and no solver was touched.
73
+ - CLI: `cli_schema_version` stays 1; previously valid invocations print
74
+ byte-identical output (checked on 11 invocations).
75
+
76
+ ### Added
77
+ - **CLI `chemthermo stability-tp`**: tangent-plane stability of a feed with
78
+ Peng-Robinson or PC-SAFT (`--eos`), JSON or text; `stable` is reported with
79
+ `stability_scope = "bounded-trial-set"`; an `inconclusive` verdict exits 3
80
+ with the payload printed. ADR-0033.
81
+ - **CLI `tp-flash --eos {peng-robinson,pc-saft}` and `--max-phases N`**:
82
+ PC-SAFT flashes (packaged parameters, `kij = 0`, phi-phi) and an explicit
83
+ phase budget; three-phase answers use the existing name-keyed layout.
84
+ `cli_schema_version` stays 1 and every previously valid invocation prints
85
+ byte-identical output. `examples/cli/stability_and_multiphase.sh`.
86
+
87
+ - **PC-SAFT temperature derivative and residual properties** (non-associating):
88
+ `PCSAFTEOS.residual_helmholtz_temperature_derivative` and
89
+ `PCSAFTEOS.residual_properties` (`h_res`, `u_res`, `s_res_tv/tp`,
90
+ `g_res_tv/tp`, reduced). Checked against teqp `get_Ar10` (<= 5.2e-16 relative
91
+ over 14 states), Gibbs-Helmholtz through the fugacity route, and
92
+ `dH_vap = T dS_vap` at saturation. Associating mixtures raise `ModelError`.
93
+ ADR-0034; `examples/basic/pcsaft_residual_properties_demo.py`.
94
+
95
+ ### Changed (tests and policy only; no library code)
96
+ - Guards that compare against floats captured on macOS arm64 are exact there
97
+ and, on any other platform, exact on every discrete field and bounded on
98
+ floats (1e-12 flash fixture, 5e-14 PC-SAFT literals); last-bit ties are
99
+ counted as ties. Makes the Linux CI and cloud runs green without weakening
100
+ the capture-platform check. ADR-0032; ledger Cases P-11 and P-17.
101
+
102
+ ### Known limitations found
103
+ - One polymer ladder state (Mw 53000, 15 wt%, 8.1 MPa) refuses at 1 of 17
104
+ pressures within +-8 ULP of the grid point, and its solver route depends on
105
+ the last bit; every converged answer is the same tie line.
106
+ - `stability_tp` breaks an exact `tpd` tie by trial order, so the reported
107
+ `trial_composition` can be the less-converged of two tied trials (good to
108
+ the stationarity tolerance, 1e-10 residual).
109
+
110
+ ## 0.2.0b1 (2026-09-25) - prerelease
111
+
112
+ First release of the phase-equilibrium campaign (121 commits and 38
113
+ distinct `Slice:` trailers since `v0.1.0`; ADR-0003 to ADR-0031). A prerelease because its
114
+ validation comes from one development machine plus the release gates of
115
+ ADR-0031, and because the CLI does not yet expose the equilibrium work.
116
+
117
+ ### Added
118
+ - **Phase stability** `chemthermo.stability_tp` (Michelsen tangent-plane
119
+ distance) with `StabilityResult` / `StabilitySettings` / `StabilityTrial`,
120
+ incipient-phase compositions and per-trial diagnostics, for an equation of
121
+ state, an activity model alone (liquid-liquid), or an activity liquid against
122
+ an ideal-gas vapour (`vapor="ideal"`). ADR-0005, 0007, 0010, 0012, 0021, 0025.
123
+ - **Phase-count discovery in `flash_tp`**: one, two or three phases found by
124
+ stability analysis, a verified split, post-split stability of every phase,
125
+ and phase addition/removal (`FlashSettings.max_phases`, default 3), on the
126
+ EOS (`phi-phi`) and `modified-raoult` paths; liquid-liquid `gamma-gamma`
127
+ mode (two phases). ADR-0008, 0009, 0011, 0016, 0019, 0020, 0024, 0026, 0029.
128
+ - **PC-SAFT** `chemthermo.PCSAFTEOS`: Gross-Sadowski (2001) hard chain +
129
+ dispersion with the 2002 association term, analytic composition/density
130
+ derivatives, density roots, log-space fugacities for long chains; packaged
131
+ parameters for 11 non-associating compounds; user records incl. association
132
+ (`PCSAFTRecord`, `PCSAFTAssociationRecord`) and polymers via
133
+ `segments_per_g` + `Component.custom(...)`. ADR-0014, 0015, 0018, 0022.
134
+ - Peng-Robinson `kij` matrices (ADR-0006); phase labels by compressibility
135
+ (ADR-0017).
136
+ - CLI `chemthermo tp-flash` (`cli_schema_version` 1; Peng-Robinson phi-phi and
137
+ deprecated gamma-phi; exit codes 0/1/2/3). ADR-0003, 0004.
138
+ - Internal (not public API) benchmark and robustness harness
139
+ `python -m chemthermo.bench` (ADR-0023, 0027) and a call-local EOS solve memo
140
+ (ADR-0030).
141
+
142
+ ### Changed / compatibility
143
+ - `NRTL.activity_coefficients` now implements the standard Renon-Prausnitz
144
+ equation (column sums); values for **asymmetric** parameters differ from
145
+ `v0.1.0`, which violated Gibbs-Duhem. Bug fix, not a model change.
146
+ - `flash_tp`: `eos` is optional; `flash_mode=None` infers the mode; phi-phi
147
+ phase detection defaults to `"tangent-plane"` (`"wilson-heuristic"` keeps the
148
+ old behaviour). Single-phase tangent-plane results no longer carry
149
+ `k_min`/`k_max`/`max_delta_k`/`rr_*` diagnostics.
150
+ - `flash_mode="gamma-phi"` and the `chemthermo.vlle` plugin boundary are
151
+ **deprecated** (docs only; still work). ADR-0013.
152
+ - Package version moves from `0.0.0` to `0.2.0b1`. (The existing `v0.1.0`
153
+ tag points at a commit whose metadata says `0.0.0`; it is left as published.)
154
+
155
+ ### Known limitations
156
+ - `stability_tp` "stable" means no negative tangent-plane distance was found
157
+ from a bounded deterministic trial set - not a proof of global stability.
158
+ - PC-SAFT parameters and the association equation rest on secondary sources
159
+ (primary papers not read); polymer parameters are a labelled test fixture
160
+ from one secondary source and are **not packaged**; polymers are monodisperse.
161
+ - No temperature derivatives for PC-SAFT: no residual enthalpy/entropy or
162
+ caloric properties.
163
+ - The robustness map (2505 states, macOS arm64) refuses 5 states, all in the
164
+ deprecated gamma-phi path by design; it measures coverage, not correctness.
165
+ - The CLI does not expose stability, multiphase flash or PC-SAFT yet.
166
+ - Default test suite takes ~4-5 min; `pytest -m slow` and the full sweep
167
+ (~37 min) are not run by CI.
168
+
169
+ ## 0.1.0
170
+
171
+ Tag `v0.1.0` on `a7a8ca7` (Feb 2026). No GitHub release was created and its
172
+ package metadata reads `0.0.0`.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ahmad Alkadri
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,11 @@
1
+ # sdist contents: the library, its metadata and user-facing docs.
2
+ # tests/ is excluded on purpose: several tests read fixtures that are not
3
+ # redistributable (e.g. DECHEMA-derived NRTL data, test-only by ADR policy),
4
+ # so a partial test tree would not run. Run the tests from a git checkout.
5
+ include LICENSE README.md CHANGELOG.md
6
+ prune tests
7
+ prune .agents
8
+ prune benchmarks
9
+ prune notebooks
10
+ prune database
11
+ prune tools
@@ -0,0 +1,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: chemthermo
3
+ Version: 0.4.0
4
+ Summary: Phase equilibrium for chemical engineering: tangent-plane stability, multiphase TP flash, Peng-Robinson, PC-SAFT and NRTL.
5
+ Author: Ahmad Alkadri
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/AhmadAlkadri/Chemical-Thermodynamics
8
+ Project-URL: Documentation, https://github.com/AhmadAlkadri/Chemical-Thermodynamics/tree/main/docs
9
+ Project-URL: Changelog, https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/CHANGELOG.md
10
+ Project-URL: Issues, https://github.com/AhmadAlkadri/Chemical-Thermodynamics/issues
11
+ Keywords: thermodynamics,phase equilibrium,flash,stability,PC-SAFT,Peng-Robinson,NRTL,chemical engineering
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Intended Audience :: Education
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
22
+ Classifier: Topic :: Scientific/Engineering :: Physics
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.11
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: numpy>=1.24
28
+ Requires-Dist: pydantic>=2.0
29
+ Requires-Dist: bibtexparser<2,>=1.4.0
30
+ Provides-Extra: dev
31
+ Requires-Dist: build>=1.2.2; extra == "dev"
32
+ Requires-Dist: twine>=5; extra == "dev"
33
+ Requires-Dist: nbstripout>=0.7.1; extra == "dev"
34
+ Requires-Dist: pytest>=7.4; extra == "dev"
35
+ Requires-Dist: ruff==0.14.13; extra == "dev"
36
+ Requires-Dist: pyright>=1.1.350; extra == "dev"
37
+ Provides-Extra: validation
38
+ Requires-Dist: thermo>=0.6.0; extra == "validation"
39
+ Requires-Dist: teqp>=0.23; extra == "validation"
40
+ Requires-Dist: feos>=0.10; extra == "validation"
41
+ Dynamic: license-file
42
+
43
+ # chemthermo
44
+
45
+ Phase equilibrium for chemical engineering in Python: tangent-plane
46
+ stability, multiphase TP flash, Peng-Robinson, PC-SAFT (with association and
47
+ polymers) and NRTL, in SI units, with every numerical claim traceable to a
48
+ recorded cross-check.
49
+
50
+ **Status: beta (0.4.0).** The science is checked against independent
51
+ implementations, but the public API may still change before 1.0. Python
52
+ >= 3.11; tested on macOS arm64 and Linux x86_64. MIT licence.
53
+
54
+ ## Install
55
+
56
+ ```bash
57
+ pip install chemthermo
58
+ ```
59
+
60
+ or pin a tagged commit from GitHub:
61
+
62
+ ```bash
63
+ pip install "chemthermo @ git+https://github.com/AhmadAlkadri/Chemical-Thermodynamics.git@v0.4.0"
64
+ ```
65
+
66
+ Runtime dependencies: numpy, pydantic, bibtexparser (< 2).
67
+
68
+ ## Quick start
69
+
70
+ A flash that decides for itself how many phases there are:
71
+
72
+ ```python
73
+ import chemthermo as ct
74
+
75
+ mixture = ct.Mixture.from_database(["Methane", "Ethane", "Propane"], [0.5, 0.3, 0.2])
76
+ result = ct.flash_tp(mixture, temperature_K=240.0, pressure_Pa=3.0e6, eos=ct.PengRobinsonEOS())
77
+
78
+ print(result.phase_names()) # ['liquid', 'vapor']
79
+ print(result.vapor_fraction) # 0.468...
80
+ print(result.phases["vapor"].composition.fractions)
81
+ ```
82
+
83
+ Stability of a feed, and the phase it would split off:
84
+
85
+ ```python
86
+ check = ct.stability_tp(
87
+ ct.Mixture.from_database(["Methane", "n-Hexane"], [0.5, 0.5]),
88
+ temperature_K=300.0, pressure_Pa=2.0e6, eos=ct.PengRobinsonEOS(),
89
+ )
90
+ print(check.status, check.tpd_min) # unstable -1.2558...
91
+ print(check.phase_branch, check.trial_composition)
92
+ ```
93
+
94
+ Three liquids, PC-SAFT, and residual properties:
95
+
96
+ ```python
97
+ from chemthermo.eos import PCSAFTEOS
98
+
99
+ three = ct.flash_tp(
100
+ ct.Mixture.from_database(["Water", "Ethanol", "n-Hexane"], [0.2, 0.4, 0.4]),
101
+ temperature_K=280.0, pressure_Pa=101325.0, eos=ct.PengRobinsonEOS(),
102
+ )
103
+ print(three.phase_names()) # ['liquid1', 'liquid2', 'liquid3']
104
+
105
+ water = PCSAFTEOS(components=("Water",))
106
+ rho = max(water.density_roots(temperature_K=300.0, pressure_Pa=1.0e5, composition=[1.0]))
107
+ props = water.residual_properties(temperature_K=300.0, density_mol_m3=rho, composition=[1.0])
108
+ print(props["h_res"], props["s_res_tp"]) # H^res/RT and S^res/R (ideal gas at same T, P)
109
+ ```
110
+
111
+ From the command line:
112
+
113
+ ```bash
114
+ chemthermo tp-flash --components Methane,Ethane,Propane --z 0.5,0.3,0.2 \
115
+ --temperature-k 240 --pressure-pa 3e6 --format json
116
+ chemthermo stability-tp --components Methane,n-Hexane --z 0.5,0.5 \
117
+ --temperature-k 300 --pressure-pa 2e6 --eos pc-saft
118
+ ```
119
+
120
+ ## What it does
121
+
122
+ | Capability | Models | Checked against (ledger case) |
123
+ | --- | --- | --- |
124
+ | Tangent-plane stability, incipient-phase composition (`stability_tp`) | Peng-Robinson, PC-SAFT, NRTL (liquid-liquid), NRTL + ideal gas | `thermo` 0.6 Michelsen test, same verdicts (S-4); Tessier et al. (2000) published global minima to 2e-11 (S-6, S-7); teqp (P-4) |
125
+ | TP flash with automatic phase count, 1-3 phases (`flash_tp`) | Peng-Robinson and PC-SAFT (`phi-phi`), NRTL (`gamma-gamma`), NRTL + Raoult (`modified-raoult`) | `thermo` `FlashVL` (F-1); teqp's traced PC-SAFT isotherm, tie lines to 2e-9 (P-5); FeOs flash and chemical potentials (P-7, P-8); a published multiphase Rachford-Rice table (V-4); a ternary VLLE tie triangle (V-1) |
126
+ | Peng-Robinson with per-pair `kij` | cubic EOS | `thermo` PRMIX (K-1); agreement floored at ~1e-4 in `ln phi` by chemthermo's rounded constants (S-4) |
127
+ | PC-SAFT residual Helmholtz, `Z`, `ln phi`, density roots | Gross & Sadowski 2001 | teqp, better than 3e-14 (P-1, P-3) |
128
+ | PC-SAFT association (2B scheme) | Gross & Sadowski 2002 | FeOs, association term to 3e-15 (P-6) |
129
+ | PC-SAFT polymers (segments per mass, long chains in log space) | monodisperse chains | FeOs, 5e-12 with matched constants (P-12 - P-14) |
130
+ | PC-SAFT residual `H`, `S`, `U`, `G` and `d(A^res/RT)/dT` | incl. association | teqp `Ar10` to 5e-16 (P-19); FeOs residual entropy/enthalpy to 2e-15 (P-20) |
131
+ | NRTL activity coefficients | NRTL | `thermo` NRTL to 9e-16 (N-2) |
132
+ | Command line: `tp-flash`, `stability-tp` | PR, PC-SAFT | golden JSON fixtures; exit-code contract |
133
+
134
+ Packaged data: critical constants, acentric factors and Antoine coefficients
135
+ for **82 components** (from Koretsky, *Engineering and Chemical
136
+ Thermodynamics*); PC-SAFT parameters for **16** (11 non-associating, plus
137
+ water, methanol, ethanol, 1-propanol and n-butanol with 2B association).
138
+
139
+ **What "checked" means here.** The comparisons above are code against
140
+ independent implementations (teqp, FeOs, `thermo`) or published worked
141
+ problems. They show the equations are implemented correctly. They say nothing
142
+ about how well a model with these parameters matches experiment, and nothing
143
+ in this repository claims that.
144
+
145
+ ## Limits, stated plainly
146
+
147
+ - **"Stable" is not a proof.** It means no negative tangent-plane distance was
148
+ found from a deterministic set of trial compositions. A phase that no trial
149
+ reaches can be missed, and a flash's phase count inherits that limit.
150
+ - **Bring your own interaction parameters.** No binary `kij` table ships.
151
+ The two packaged NRTL pairs are **synthetic placeholders** for demos: real
152
+ NRTL work needs your own parameters (`NRTLParameters.from_pairs`). PC-SAFT
153
+ with `kij = 0` gets water / hydrocarbon mutual solubilities badly wrong.
154
+ - **Residual properties only.** No ideal-gas heat capacities are packaged, so
155
+ no total enthalpy, entropy or `Cp`; no `Cp^res` yet.
156
+ - **PC-SAFT scope:** no polar terms; only the 2B association scheme is
157
+ validated; no induced association; polymers are monodisperse; no polymer
158
+ parameters are packaged.
159
+ - **Modified Raoult is a low-pressure model** (ideal vapour, no Poynting
160
+ correction); Antoine ranges are enforced, never extrapolated.
161
+ - **Cost:** a Peng-Robinson or activity-model flash takes milliseconds; PC-SAFT
162
+ flashes take up to a few seconds (polymer and associating states the
163
+ longest), and a three-phase PC-SAFT flash about 35 s.
164
+ - **Deprecated:** `flash_mode="gamma-phi"` (kept for the CLI v1 contract;
165
+ emits `DeprecationWarning`). `chemthermo.vlle` was removed in 0.4.0.
166
+
167
+ Longer, model-specific limits are in the docs below.
168
+
169
+ ## Documentation
170
+
171
+ - [Installation and development setup](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/installation.md)
172
+ - [TP flash](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/flash.md) - phase detection, flash modes, three phases, `kij`, NRTL
173
+ - [Phase stability](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/stability.md)
174
+ - [PC-SAFT](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/pcsaft.md) - parameters, association, polymers, residual properties, limits and their validation
175
+ - [Command line](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/cli.md)
176
+ - [Extending with a new equation of state](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/extending.md)
177
+ - [Benchmarks and the robustness map](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/benchmarks.md)
178
+ - Runnable scripts: [`examples/`](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/examples/README.md); notebooks: [`notebooks/`](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/notebooks/README.md)
179
+ - [Changelog](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/CHANGELOG.md)
180
+
181
+ ## How it is validated and developed
182
+
183
+ Every number quoted above has an entry in the validation ledger,
184
+ [`.agents/brain/validation-cases.md`](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/.agents/brain/validation-cases.md), with
185
+ its source, tolerance, achieved value and test. Design decisions are
186
+ recorded as ADRs in [`.agents/brain/adr/`](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/tree/main/.agents/brain/adr/). The tests that
187
+ compare against teqp, FeOs and `thermo` run with `pip install -e
188
+ ".[validation]"` and skip cleanly otherwise. A 2505-state robustness map
189
+ (`python -m chemthermo.bench robustness`) sweeps every model family; its only
190
+ refusals are 5 states of the deprecated gamma-phi path.
191
+
192
+ Contributions: see [CONTRIBUTING.md](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/CONTRIBUTING.md).
193
+
194
+ ## Licence
195
+
196
+ MIT - see [LICENSE](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/LICENSE).
@@ -0,0 +1,154 @@
1
+ # chemthermo
2
+
3
+ Phase equilibrium for chemical engineering in Python: tangent-plane
4
+ stability, multiphase TP flash, Peng-Robinson, PC-SAFT (with association and
5
+ polymers) and NRTL, in SI units, with every numerical claim traceable to a
6
+ recorded cross-check.
7
+
8
+ **Status: beta (0.4.0).** The science is checked against independent
9
+ implementations, but the public API may still change before 1.0. Python
10
+ >= 3.11; tested on macOS arm64 and Linux x86_64. MIT licence.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pip install chemthermo
16
+ ```
17
+
18
+ or pin a tagged commit from GitHub:
19
+
20
+ ```bash
21
+ pip install "chemthermo @ git+https://github.com/AhmadAlkadri/Chemical-Thermodynamics.git@v0.4.0"
22
+ ```
23
+
24
+ Runtime dependencies: numpy, pydantic, bibtexparser (< 2).
25
+
26
+ ## Quick start
27
+
28
+ A flash that decides for itself how many phases there are:
29
+
30
+ ```python
31
+ import chemthermo as ct
32
+
33
+ mixture = ct.Mixture.from_database(["Methane", "Ethane", "Propane"], [0.5, 0.3, 0.2])
34
+ result = ct.flash_tp(mixture, temperature_K=240.0, pressure_Pa=3.0e6, eos=ct.PengRobinsonEOS())
35
+
36
+ print(result.phase_names()) # ['liquid', 'vapor']
37
+ print(result.vapor_fraction) # 0.468...
38
+ print(result.phases["vapor"].composition.fractions)
39
+ ```
40
+
41
+ Stability of a feed, and the phase it would split off:
42
+
43
+ ```python
44
+ check = ct.stability_tp(
45
+ ct.Mixture.from_database(["Methane", "n-Hexane"], [0.5, 0.5]),
46
+ temperature_K=300.0, pressure_Pa=2.0e6, eos=ct.PengRobinsonEOS(),
47
+ )
48
+ print(check.status, check.tpd_min) # unstable -1.2558...
49
+ print(check.phase_branch, check.trial_composition)
50
+ ```
51
+
52
+ Three liquids, PC-SAFT, and residual properties:
53
+
54
+ ```python
55
+ from chemthermo.eos import PCSAFTEOS
56
+
57
+ three = ct.flash_tp(
58
+ ct.Mixture.from_database(["Water", "Ethanol", "n-Hexane"], [0.2, 0.4, 0.4]),
59
+ temperature_K=280.0, pressure_Pa=101325.0, eos=ct.PengRobinsonEOS(),
60
+ )
61
+ print(three.phase_names()) # ['liquid1', 'liquid2', 'liquid3']
62
+
63
+ water = PCSAFTEOS(components=("Water",))
64
+ rho = max(water.density_roots(temperature_K=300.0, pressure_Pa=1.0e5, composition=[1.0]))
65
+ props = water.residual_properties(temperature_K=300.0, density_mol_m3=rho, composition=[1.0])
66
+ print(props["h_res"], props["s_res_tp"]) # H^res/RT and S^res/R (ideal gas at same T, P)
67
+ ```
68
+
69
+ From the command line:
70
+
71
+ ```bash
72
+ chemthermo tp-flash --components Methane,Ethane,Propane --z 0.5,0.3,0.2 \
73
+ --temperature-k 240 --pressure-pa 3e6 --format json
74
+ chemthermo stability-tp --components Methane,n-Hexane --z 0.5,0.5 \
75
+ --temperature-k 300 --pressure-pa 2e6 --eos pc-saft
76
+ ```
77
+
78
+ ## What it does
79
+
80
+ | Capability | Models | Checked against (ledger case) |
81
+ | --- | --- | --- |
82
+ | Tangent-plane stability, incipient-phase composition (`stability_tp`) | Peng-Robinson, PC-SAFT, NRTL (liquid-liquid), NRTL + ideal gas | `thermo` 0.6 Michelsen test, same verdicts (S-4); Tessier et al. (2000) published global minima to 2e-11 (S-6, S-7); teqp (P-4) |
83
+ | TP flash with automatic phase count, 1-3 phases (`flash_tp`) | Peng-Robinson and PC-SAFT (`phi-phi`), NRTL (`gamma-gamma`), NRTL + Raoult (`modified-raoult`) | `thermo` `FlashVL` (F-1); teqp's traced PC-SAFT isotherm, tie lines to 2e-9 (P-5); FeOs flash and chemical potentials (P-7, P-8); a published multiphase Rachford-Rice table (V-4); a ternary VLLE tie triangle (V-1) |
84
+ | Peng-Robinson with per-pair `kij` | cubic EOS | `thermo` PRMIX (K-1); agreement floored at ~1e-4 in `ln phi` by chemthermo's rounded constants (S-4) |
85
+ | PC-SAFT residual Helmholtz, `Z`, `ln phi`, density roots | Gross & Sadowski 2001 | teqp, better than 3e-14 (P-1, P-3) |
86
+ | PC-SAFT association (2B scheme) | Gross & Sadowski 2002 | FeOs, association term to 3e-15 (P-6) |
87
+ | PC-SAFT polymers (segments per mass, long chains in log space) | monodisperse chains | FeOs, 5e-12 with matched constants (P-12 - P-14) |
88
+ | PC-SAFT residual `H`, `S`, `U`, `G` and `d(A^res/RT)/dT` | incl. association | teqp `Ar10` to 5e-16 (P-19); FeOs residual entropy/enthalpy to 2e-15 (P-20) |
89
+ | NRTL activity coefficients | NRTL | `thermo` NRTL to 9e-16 (N-2) |
90
+ | Command line: `tp-flash`, `stability-tp` | PR, PC-SAFT | golden JSON fixtures; exit-code contract |
91
+
92
+ Packaged data: critical constants, acentric factors and Antoine coefficients
93
+ for **82 components** (from Koretsky, *Engineering and Chemical
94
+ Thermodynamics*); PC-SAFT parameters for **16** (11 non-associating, plus
95
+ water, methanol, ethanol, 1-propanol and n-butanol with 2B association).
96
+
97
+ **What "checked" means here.** The comparisons above are code against
98
+ independent implementations (teqp, FeOs, `thermo`) or published worked
99
+ problems. They show the equations are implemented correctly. They say nothing
100
+ about how well a model with these parameters matches experiment, and nothing
101
+ in this repository claims that.
102
+
103
+ ## Limits, stated plainly
104
+
105
+ - **"Stable" is not a proof.** It means no negative tangent-plane distance was
106
+ found from a deterministic set of trial compositions. A phase that no trial
107
+ reaches can be missed, and a flash's phase count inherits that limit.
108
+ - **Bring your own interaction parameters.** No binary `kij` table ships.
109
+ The two packaged NRTL pairs are **synthetic placeholders** for demos: real
110
+ NRTL work needs your own parameters (`NRTLParameters.from_pairs`). PC-SAFT
111
+ with `kij = 0` gets water / hydrocarbon mutual solubilities badly wrong.
112
+ - **Residual properties only.** No ideal-gas heat capacities are packaged, so
113
+ no total enthalpy, entropy or `Cp`; no `Cp^res` yet.
114
+ - **PC-SAFT scope:** no polar terms; only the 2B association scheme is
115
+ validated; no induced association; polymers are monodisperse; no polymer
116
+ parameters are packaged.
117
+ - **Modified Raoult is a low-pressure model** (ideal vapour, no Poynting
118
+ correction); Antoine ranges are enforced, never extrapolated.
119
+ - **Cost:** a Peng-Robinson or activity-model flash takes milliseconds; PC-SAFT
120
+ flashes take up to a few seconds (polymer and associating states the
121
+ longest), and a three-phase PC-SAFT flash about 35 s.
122
+ - **Deprecated:** `flash_mode="gamma-phi"` (kept for the CLI v1 contract;
123
+ emits `DeprecationWarning`). `chemthermo.vlle` was removed in 0.4.0.
124
+
125
+ Longer, model-specific limits are in the docs below.
126
+
127
+ ## Documentation
128
+
129
+ - [Installation and development setup](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/installation.md)
130
+ - [TP flash](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/flash.md) - phase detection, flash modes, three phases, `kij`, NRTL
131
+ - [Phase stability](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/stability.md)
132
+ - [PC-SAFT](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/pcsaft.md) - parameters, association, polymers, residual properties, limits and their validation
133
+ - [Command line](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/cli.md)
134
+ - [Extending with a new equation of state](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/extending.md)
135
+ - [Benchmarks and the robustness map](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/docs/benchmarks.md)
136
+ - Runnable scripts: [`examples/`](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/examples/README.md); notebooks: [`notebooks/`](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/notebooks/README.md)
137
+ - [Changelog](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/CHANGELOG.md)
138
+
139
+ ## How it is validated and developed
140
+
141
+ Every number quoted above has an entry in the validation ledger,
142
+ [`.agents/brain/validation-cases.md`](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/.agents/brain/validation-cases.md), with
143
+ its source, tolerance, achieved value and test. Design decisions are
144
+ recorded as ADRs in [`.agents/brain/adr/`](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/tree/main/.agents/brain/adr/). The tests that
145
+ compare against teqp, FeOs and `thermo` run with `pip install -e
146
+ ".[validation]"` and skip cleanly otherwise. A 2505-state robustness map
147
+ (`python -m chemthermo.bench robustness`) sweeps every model family; its only
148
+ refusals are 5 states of the deprecated gamma-phi path.
149
+
150
+ Contributions: see [CONTRIBUTING.md](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/CONTRIBUTING.md).
151
+
152
+ ## Licence
153
+
154
+ MIT - see [LICENSE](https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/LICENSE).
@@ -0,0 +1,103 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "chemthermo"
7
+ version = "0.4.0"
8
+ description = "Phase equilibrium for chemical engineering: tangent-plane stability, multiphase TP flash, Peng-Robinson, PC-SAFT and NRTL."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Ahmad Alkadri" }]
14
+ keywords = [
15
+ "thermodynamics",
16
+ "phase equilibrium",
17
+ "flash",
18
+ "stability",
19
+ "PC-SAFT",
20
+ "Peng-Robinson",
21
+ "NRTL",
22
+ "chemical engineering",
23
+ ]
24
+ classifiers = [
25
+ "Development Status :: 4 - Beta",
26
+ "Intended Audience :: Science/Research",
27
+ "Intended Audience :: Education",
28
+ "Operating System :: OS Independent",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3 :: Only",
31
+ "Programming Language :: Python :: 3.11",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Programming Language :: Python :: 3.13",
34
+ "Topic :: Scientific/Engineering :: Chemistry",
35
+ "Topic :: Scientific/Engineering :: Physics",
36
+ "Typing :: Typed",
37
+ ]
38
+ dependencies = [
39
+ "numpy>=1.24",
40
+ "pydantic>=2.0",
41
+ "bibtexparser>=1.4.0,<2",
42
+ ]
43
+
44
+ [project.urls]
45
+ Homepage = "https://github.com/AhmadAlkadri/Chemical-Thermodynamics"
46
+ Documentation = "https://github.com/AhmadAlkadri/Chemical-Thermodynamics/tree/main/docs"
47
+ Changelog = "https://github.com/AhmadAlkadri/Chemical-Thermodynamics/blob/main/CHANGELOG.md"
48
+ Issues = "https://github.com/AhmadAlkadri/Chemical-Thermodynamics/issues"
49
+
50
+ [project.scripts]
51
+ chemthermo = "chemthermo.cli:main"
52
+
53
+ [project.optional-dependencies]
54
+ dev = [
55
+ "build>=1.2.2",
56
+ "twine>=5",
57
+ "nbstripout>=0.7.1",
58
+ "pytest>=7.4",
59
+ "ruff==0.14.13",
60
+ "pyright>=1.1.350",
61
+ ]
62
+ validation = [
63
+ "thermo>=0.6.0",
64
+ "teqp>=0.23",
65
+ # FeOs is the reference for the PC-SAFT **association** term (ADR-0018):
66
+ # teqp's PCSAFT kind does not implement association. It pulls in its own
67
+ # units package, whose PyPI name is `si-units` and whose import name is
68
+ # `si_units`; it is not listed separately because feos depends on it.
69
+ "feos>=0.10",
70
+ ]
71
+
72
+ [tool.pytest.ini_options]
73
+ markers = [
74
+ "slow: a full validation grid whose representative subset runs by default (e.g. the 188-state PC-SAFT grid of Case F-4), or a repetition of a capability the default run already covers (ADR-0020); deselected by default (see addopts below), opt in with `pytest -q -m slow`. Never the only test of a capability - see `.agents/dev-contract.md`",
75
+ ]
76
+ # Deselected, not skipped, by default: `-m slow` on the command line overrides
77
+ # this addopts entry (pytest keeps the last `-m` value), so `pytest -q -m slow`
78
+ # runs exactly the slow-marked tests and nothing else. See
79
+ # `.agents/dev-contract.md` for the full-grid command and CI's choice.
80
+ addopts = "-m 'not slow'"
81
+
82
+ [tool.setuptools]
83
+ package-dir = { "" = "src" }
84
+
85
+ [tool.setuptools.packages.find]
86
+ where = ["src"]
87
+
88
+ [tool.setuptools.package-data]
89
+ "chemthermo" = ["py.typed"]
90
+ "chemthermo.data" = ["components.json", "references.bib"]
91
+ "chemthermo.parameters" = ["data/activity/nrtl.json", "data/eos/pcsaft.json"]
92
+
93
+ [tool.ruff]
94
+ target-version = "py311"
95
+ line-length = 100
96
+ exclude = [
97
+ "database",
98
+ "notebooks",
99
+ ]
100
+
101
+ [tool.ruff.lint]
102
+ ignore = ["E501"]
103
+ extend-select = ["I"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+