gliquid 0.1.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 (45) hide show
  1. gliquid-0.1.0/.github/CODEOWNERS +2 -0
  2. gliquid-0.1.0/.github/dependabot.yml +27 -0
  3. gliquid-0.1.0/.github/workflows/release.yml +128 -0
  4. gliquid-0.1.0/.github/workflows/tests.yml +125 -0
  5. gliquid-0.1.0/.gitignore +47 -0
  6. gliquid-0.1.0/CHANGELOG.md +90 -0
  7. gliquid-0.1.0/CITATION.cff +42 -0
  8. gliquid-0.1.0/CONTRIBUTING.md +130 -0
  9. gliquid-0.1.0/LICENSE +21 -0
  10. gliquid-0.1.0/PKG-INFO +352 -0
  11. gliquid-0.1.0/README.md +295 -0
  12. gliquid-0.1.0/assets/digitized_pd_anatomy.png +0 -0
  13. gliquid-0.1.0/assets/gliq_logo_tall.png +0 -0
  14. gliquid-0.1.0/assets/invariant_points_and_reactions.png +0 -0
  15. gliquid-0.1.0/notebooks/GaRu_adjustment.ipynb +5526 -0
  16. gliquid-0.1.0/notebooks/PbTb_adjustment.ipynb +5565 -0
  17. gliquid-0.1.0/notebooks/colab_demo.ipynb +164 -0
  18. gliquid-0.1.0/notebooks/fitting_demo.ipynb +20010 -0
  19. gliquid-0.1.0/notebooks/interpolation_demo.ipynb +251 -0
  20. gliquid-0.1.0/pyproject.toml +208 -0
  21. gliquid-0.1.0/requirements/min-constraints.txt +34 -0
  22. gliquid-0.1.0/scripts/run_notebooks.py +217 -0
  23. gliquid-0.1.0/src/gliquid/__init__.py +72 -0
  24. gliquid-0.1.0/src/gliquid/_version.py +24 -0
  25. gliquid-0.1.0/src/gliquid/api.py +828 -0
  26. gliquid-0.1.0/src/gliquid/binary.py +2520 -0
  27. gliquid-0.1.0/src/gliquid/config.py +316 -0
  28. gliquid-0.1.0/src/gliquid/data/omegas_hcp.json +36 -0
  29. gliquid-0.1.0/src/gliquid/data/phase_transitions.json +9748 -0
  30. gliquid-0.1.0/src/gliquid/data/spurious_structures.json +173 -0
  31. gliquid-0.1.0/src/gliquid/hsx.py +423 -0
  32. gliquid-0.1.0/src/gliquid/hull_editor.py +1176 -0
  33. gliquid-0.1.0/src/gliquid/mpds.py +1897 -0
  34. gliquid-0.1.0/src/gliquid/phase.py +469 -0
  35. gliquid-0.1.0/src/gliquid/plotting/__init__.py +7 -0
  36. gliquid-0.1.0/src/gliquid/plotting/binary_figs.py +675 -0
  37. gliquid-0.1.0/src/gliquid/plotting/binary_tx.py +2613 -0
  38. gliquid-0.1.0/src/gliquid/plotting/export.py +141 -0
  39. gliquid-0.1.0/src/gliquid/plotting/style.py +99 -0
  40. gliquid-0.1.0/src/gliquid/plotting/ternary_surface.py +369 -0
  41. gliquid-0.1.0/src/gliquid/production_model_runner.py +609 -0
  42. gliquid-0.1.0/src/gliquid/shap_compat.py +200 -0
  43. gliquid-0.1.0/src/gliquid/solution.py +1547 -0
  44. gliquid-0.1.0/src/gliquid/ternary.py +1039 -0
  45. gliquid-0.1.0/tox.ini +138 -0
@@ -0,0 +1,2 @@
1
+ # Global owner — Josh is auto-requested as reviewer on all PRs
2
+ * @willwerj
@@ -0,0 +1,27 @@
1
+ version: 2
2
+ updates:
3
+ # Keep Python dependencies up to date
4
+ - package-ecosystem: "pip"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ day: "monday"
9
+ open-pull-requests-limit: 5
10
+ reviewers:
11
+ - "willwerj"
12
+ ignore:
13
+ # These are tightly pinned for compatibility — update manually
14
+ - dependency-name: "scikit-learn"
15
+ update-types: ["version-update:semver-major", "version-update:semver-minor"]
16
+ - dependency-name: "xgboost"
17
+ update-types: ["version-update:semver-major", "version-update:semver-minor"]
18
+ - dependency-name: "emmet-core"
19
+ update-types: ["version-update:semver-major", "version-update:semver-minor"]
20
+
21
+ # Keep GitHub Actions up to date
22
+ - package-ecosystem: "github-actions"
23
+ directory: "/"
24
+ schedule:
25
+ interval: "monthly"
26
+ reviewers:
27
+ - "willwerj"
@@ -0,0 +1,128 @@
1
+ name: Release
2
+
3
+ # Tagging IS the release. hatch-vcs derives the distribution version from the tag, so there
4
+ # is no version literal to bump in src/ -- see the release checklist in CONTRIBUTING.md.
5
+ on:
6
+ push:
7
+ tags: ['v*']
8
+
9
+ # No API token appears anywhere in this file, by design. Both publish jobs use PyPI Trusted
10
+ # Publishing (OIDC): GitHub mints a short-lived identity token at job runtime from
11
+ # `permissions: id-token: write`, and the index trusts this repository + workflow + GitHub
12
+ # environment. The token-based alternative (a stored __token__ password) is deliberately not
13
+ # used -- a leaked long-lived token is exactly what Trusted Publishing removes.
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ build:
19
+ name: Build sdist and wheel
20
+ runs-on: ubuntu-latest
21
+
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ with:
25
+ # NOT optional, and the single most dangerous thing to get wrong in this file.
26
+ # hatch-vcs reads the version from git tags; the default shallow clone has none.
27
+ # The build would NOT fail -- it would silently emit the pyproject
28
+ # fallback-version (0.0.0) and publish it. That fallback is 0.0.0 rather than the
29
+ # release version precisely so this failure is visible in the artifact name.
30
+ fetch-depth: 0
31
+
32
+ - name: Set up Python
33
+ uses: actions/setup-python@v5
34
+ with:
35
+ python-version: "3.12"
36
+
37
+ - name: Install build tooling
38
+ run: |
39
+ python -m pip install --upgrade pip
40
+ pip install build twine
41
+
42
+ - name: Build
43
+ run: python -m build
44
+
45
+ - name: Check metadata
46
+ run: twine check dist/*
47
+
48
+ - name: Show built version
49
+ # Cheap tripwire for the fetch-depth failure above: a 0.0.0 filename here means the
50
+ # tag was not visible to hatch-vcs, and nothing downstream should be released.
51
+ run: ls -l dist/
52
+
53
+ - name: Upload distributions
54
+ uses: actions/upload-artifact@v4
55
+ with:
56
+ name: dist
57
+ path: dist/
58
+ if-no-files-found: error
59
+
60
+ testpypi:
61
+ name: Publish to TestPyPI
62
+ needs: [build]
63
+ runs-on: ubuntu-latest
64
+ environment: testpypi
65
+ permissions:
66
+ id-token: write # OIDC identity for Trusted Publishing; see the note at the top
67
+
68
+ steps:
69
+ - name: Download distributions
70
+ uses: actions/download-artifact@v4
71
+ with:
72
+ name: dist
73
+ path: dist/
74
+
75
+ - name: Publish to TestPyPI
76
+ uses: pypa/gh-action-pypi-publish@release/v1
77
+ with:
78
+ repository-url: https://test.pypi.org/legacy/
79
+
80
+ pypi:
81
+ name: Publish to PyPI
82
+ needs: [testpypi]
83
+ runs-on: ubuntu-latest
84
+
85
+ # LOAD-BEARING, NOT DECORATION. The `pypi` GitHub environment carries a
86
+ # required-reviewer protection rule, configured in the repository settings UI and not
87
+ # expressible in this file. That rule is the entire reason "TestPyPI first, then PyPI"
88
+ # is real rather than aspirational: the run pauses here until a maintainer has looked at
89
+ # what TestPyPI accepted and approves the deployment. Removing this line -- or deleting
90
+ # the environment because it "looks empty" -- turns an irreversible publish into an
91
+ # unattended one. PyPI cannot un-publish a version.
92
+ environment: pypi
93
+ permissions:
94
+ id-token: write # OIDC identity for Trusted Publishing; see the note at the top
95
+
96
+ steps:
97
+ - name: Download distributions
98
+ uses: actions/download-artifact@v4
99
+ with:
100
+ name: dist
101
+ path: dist/
102
+
103
+ - name: Publish to PyPI
104
+ uses: pypa/gh-action-pypi-publish@release/v1
105
+
106
+ github-release:
107
+ name: Create GitHub release
108
+ needs: [pypi]
109
+ runs-on: ubuntu-latest
110
+ permissions:
111
+ contents: write # required to create the release
112
+
113
+ steps:
114
+ - uses: actions/checkout@v4
115
+ with:
116
+ fetch-depth: 0 # see the note on the build job
117
+
118
+ - name: Download distributions
119
+ uses: actions/download-artifact@v4
120
+ with:
121
+ name: dist
122
+ path: dist/
123
+
124
+ - name: Create release and attach artifacts
125
+ env:
126
+ # The automatic, job-scoped GitHub Actions token -- not a stored credential.
127
+ GH_TOKEN: ${{ github.token }}
128
+ run: gh release create "$GITHUB_REF_NAME" dist/* --title "$GITHUB_REF_NAME" --generate-notes
@@ -0,0 +1,125 @@
1
+ name: Run Tests
2
+
3
+ # Every branch, not just main. This workflow previously triggered on main only, while the
4
+ # code being released lived ~90 commits ahead of it -- so it had never actually run against
5
+ # the package it guards.
6
+ on:
7
+ push:
8
+ branches: ['**']
9
+ pull_request:
10
+ branches: [main]
11
+
12
+ jobs:
13
+ test-cached:
14
+ name: Cached Tests (Python ${{ matrix.python-version }})
15
+ runs-on: ubuntu-latest
16
+
17
+ strategy:
18
+ # One version failing must not hide the state of the other three.
19
+ fail-fast: false
20
+ matrix:
21
+ # Mirrors requires-python = ">=3.10,<3.14" and the tox compat matrix.
22
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
23
+
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ with:
27
+ # NOT optional. hatch-vcs derives the version from the git tag, and the default
28
+ # shallow clone fetches none. Getting this wrong does not fail the checkout -- it
29
+ # silently produces the pyproject fallback-version (0.0.0), which is why that
30
+ # fallback is deliberately not the release version.
31
+ fetch-depth: 0
32
+
33
+ - name: Set up Python
34
+ uses: actions/setup-python@v5
35
+ with:
36
+ python-version: ${{ matrix.python-version }}
37
+
38
+ - name: Cache pip dependencies
39
+ uses: actions/cache@v4
40
+ with:
41
+ path: ~/.cache/pip
42
+ key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }}
43
+ restore-keys: |
44
+ ${{ runner.os }}-pip-${{ matrix.python-version }}-
45
+ ${{ runner.os }}-pip-
46
+
47
+ - name: Install package and test extra
48
+ # Install the declared extra rather than a bare `pip install pytest`, so CI
49
+ # exercises the same dependency set a contributor gets from CONTRIBUTING.md.
50
+ run: |
51
+ python -m pip install --upgrade pip
52
+ pip install -e '.[test]'
53
+
54
+ - name: Run cached tests
55
+ # CI is where the maintainer tier belongs, so both tiers run. The live Materials
56
+ # Project fetch is deselected by MARKER, not by path: test_dft_data_loading.py moved
57
+ # to tests_internal/ and carries `needs_network`, and the API job below runs it.
58
+ run: pytest tests tests_internal -v --tb=short -m "not needs_network"
59
+
60
+ test-api:
61
+ name: API Tests
62
+ runs-on: ubuntu-latest
63
+ needs: test-cached
64
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
65
+
66
+ steps:
67
+ - uses: actions/checkout@v4
68
+ with:
69
+ fetch-depth: 0 # see the note on the cached job
70
+
71
+ - name: Set up Python
72
+ uses: actions/setup-python@v5
73
+ with:
74
+ python-version: "3.12"
75
+
76
+ - name: Cache pip dependencies
77
+ uses: actions/cache@v4
78
+ with:
79
+ path: ~/.cache/pip
80
+ key: ${{ runner.os }}-pip-3.12-${{ hashFiles('pyproject.toml') }}
81
+ restore-keys: |
82
+ ${{ runner.os }}-pip-3.12-
83
+ ${{ runner.os }}-pip-
84
+
85
+ - name: Install package and test extra
86
+ run: |
87
+ python -m pip install --upgrade pip
88
+ pip install -e '.[test]'
89
+
90
+ - name: Run API tests
91
+ env:
92
+ NEW_MP_API_KEY: ${{ secrets.NEW_MP_API_KEY }}
93
+ run: pytest tests_internal/test_dft_data_loading.py -v --tb=short
94
+
95
+ lint:
96
+ name: Lint and Format
97
+ runs-on: ubuntu-latest
98
+
99
+ # NON-BLOCKING ON PURPOSE, for one cycle. `ruff format` landed in spec 04 but
100
+ # `ruff check` still has a backlog of findings; failing every push on it would
101
+ # red-wall the repo before anyone could read the list. The job exists so the backlog
102
+ # is VISIBLE in the checks tab. Flip this to false (or just delete the line) once the
103
+ # backlog is burned down -- leaving it here permanently makes the job decorative.
104
+ continue-on-error: true
105
+
106
+ steps:
107
+ - uses: actions/checkout@v4
108
+ with:
109
+ fetch-depth: 0 # see the note on the cached job
110
+
111
+ - name: Set up Python
112
+ uses: actions/setup-python@v5
113
+ with:
114
+ python-version: "3.12"
115
+
116
+ - name: Install package and test extra
117
+ run: |
118
+ python -m pip install --upgrade pip
119
+ pip install -e '.[test]'
120
+
121
+ - name: Ruff lint
122
+ run: ruff check src/gliquid tests tests_internal
123
+
124
+ - name: Ruff format check
125
+ run: ruff format --check src/gliquid tests tests_internal
@@ -0,0 +1,47 @@
1
+ notebooks/constraint_comparison.ipynb
2
+ notebooks/_executed/
3
+
4
+ # tox / compat testing
5
+ .tox/
6
+ compat-test-phase1.log
7
+
8
+ # Python build / cache / packaging artifacts
9
+ __pycache__/
10
+ *.py[cod]
11
+ build/
12
+ *.egg-info/
13
+ # Written by the hatch-vcs build hook from the git tag; regenerated on every build.
14
+ src/gliquid/_version.py
15
+
16
+ # Logs
17
+ *.log
18
+
19
+ # Reagent knowledge-graph database (local only)
20
+ .reagent/
21
+
22
+ # Editor/IDE local config
23
+ .vscode/
24
+
25
+ # Generated data & local config (kept untracked on main)
26
+ # tox.ini is deliberately NOT here: the cross-version compat matrix is part of the project,
27
+ # and a contributor cannot reproduce it if the file is untracked.
28
+ .claude/
29
+ # requirements/ is deliberately NOT ignored: tox.ini (tracked) drives the min half of the
30
+ # compat matrix from requirements/min-constraints.txt, so ignoring it would leave the
31
+ # matrix unreproducible from a clone -- the same reason tox.ini itself is tracked.
32
+ CONTEXT.md
33
+ data/fit_results_cache_*
34
+ figures/benchmark_*/
35
+ # Per-system DFT entry caches fetched on demand from the Materials Project. A hand-picked
36
+ # set of these IS tracked (the fixtures the test suite reads); this pattern only stops
37
+ # NEWLY fetched ones showing up as untracked noise. Ignoring a path does not untrack
38
+ # anything already in the index, so the committed corpus is unaffected.
39
+ data/*_ENTRIES_MP_GGA.json
40
+
41
+ # Local secrets (API keys) - never commit
42
+ .env
43
+ .env.*
44
+
45
+ scripts/build_branch_feature_cache.py
46
+ tests_internal/test_branch_feature_cache.py
47
+ tests/_figures/
@@ -0,0 +1,90 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project
6
+ follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The distribution version is
7
+ derived from the git tag by `hatch-vcs` — tagging `vX.Y.Z` *is* the release — so nothing in the
8
+ source tree carries a version literal that could disagree with this file.
9
+
10
+ ## [Unreleased]
11
+
12
+ ## [0.1.0] - 2026-08-12
13
+
14
+ First public release. `gliquid` was developed privately before this point, so there are no
15
+ earlier published versions to diff against; this entry describes what the package **is** at
16
+ 0.1.0 rather than what changed.
17
+
18
+ ### Added
19
+
20
+ - **DFT-referenced binary liquid fitting** (`gliquid.binary`). `BinaryLiquid` assembles a
21
+ two-component system from cached Materials Project DFT entries plus a digitized experimental
22
+ phase diagram, and `fit_parameters()` optimizes non-ideal liquid mixing parameters against the
23
+ measured phase boundaries, reporting per-fit MAE. `BinaryLiquid.from_cache()` is the usual
24
+ entry point.
25
+ - **Solution models** (`gliquid.solution`). `SolutionModel` and the `RKPolyExp`
26
+ Redlich–Kister/exponential family, with four registered parameter formats — `linear`,
27
+ `combined`, `comb-exp`, `regular` — selected by name through `param_format=`, plus the
28
+ temperature scale `tau`.
29
+ - **Phase-equilibrium machinery** (`gliquid.hsx`). `HSX` and `lower_convex_hull` build the
30
+ enthalpy–entropy–composition lower convex hull that turns free-energy curves into phase
31
+ fields, liquidus/solidus boundaries and invariant points.
32
+ - **Ternary interpolation** (`gliquid.ternary`). `TernaryLiquidInterpolation` interpolates a
33
+ ternary liquid free-energy surface from three fitted binary sub-systems, with `TLIPlotter`
34
+ for isothermal sections and liquidus-surface views.
35
+ - **Unary reference database** (`gliquid.phase`). `UNARY`, `ComponentRef` and `Phase` expose
36
+ per-element melting points, transition temperatures and lattice stabilities used as the
37
+ reference states for every mixing calculation.
38
+ - **Experimental phase-diagram ingest** (`gliquid.mpds`). `load_mpds_data()` reads digitized
39
+ MPDS diagrams, and `identify_invariant_points()` extracts eutectics, peritectics and
40
+ congruent points from them.
41
+ - **Plotting layer** (`gliquid.plotting`, plus the `BLPlotter`/`TLIPlotter` façades). Plotly
42
+ binary T–x diagrams, convex-hull and free-energy views, ternary surfaces, a shared style/color
43
+ module, and figure export helpers.
44
+ - **Interactive hull editor** (`gliquid.hull_editor`). `ConvexHullEditor` is an `ipywidgets`
45
+ tool for hand-adjusting hull endpoints; the module imports on a bare install and raises a
46
+ message naming the `editor` extra only when one is actually constructed.
47
+ - **Pre-trained model runner** (`gliquid.production_model_runner`). Loads an exported L0/L1
48
+ model bundle, predicts from single-row frames while preserving the L1 antisymmetric
49
+ constraint, and renders compact SHAP force plots.
50
+ - **Bundled reference tables.** `phase_transitions.json`, `omegas_hcp.json` and
51
+ `spurious_structures.json` ship inside the wheel at `gliquid/data/`, so element free-energy
52
+ references work immediately after `pip install gliquid` with no external files.
53
+ - **External data-corpus contract** (`gliquid.config`). The per-system DFT entry caches,
54
+ digitized diagrams and model bundle are megabytes of per-system data that no distribution
55
+ carries. They are located through `set_data_dir()`, then `GLIQUID_DATA_DIR`, then a source
56
+ checkout's own `data/`; with none of the three available a call that needs the corpus raises
57
+ `ConfigError` naming both remedies rather than guessing a directory. Each shipped reference
58
+ table is overridden by a same-named file in the data directory when one is present.
59
+ - **Optional extras.** `mpds` (live MPDS downloads), `editor` (`ConvexHullEditor` widgets),
60
+ `models` (the exact `scikit-learn`/`xgboost` versions the serialized model artifacts were
61
+ pickled against), `notebook` (local Jupyter tooling), `test` (`pytest`, `ruff`).
62
+ - **Library-grade logging.** All output goes through the `gliquid` logger tree, one child
63
+ logger per module; the package installs no handlers and sets no levels, leaving that to the
64
+ application. `tests/test_logging_boundary.py` enforces the boundary against the source tree,
65
+ with two documented exemptions (`mpds.print_phase_mismatch_chart`, `hull_editor._log`).
66
+ - **Demonstration notebooks.** `notebooks/fitting_demo.ipynb`,
67
+ `notebooks/interpolation_demo.ipynb` and a Colab-ready `notebooks/colab_demo.ipynb`.
68
+ - **Two-tier test suite.** A public `tests/` suite plus a maintainer `tests_internal/` tier of
69
+ value pins, figure goldens and cache/network-gated families, with `pins`, `needs_cache`,
70
+ `needs_network` and `slow` markers under `--strict-markers`. See `CONTRIBUTING.md`.
71
+ - **Packaging.** Hatchling with `hatch-vcs`, so the version is single-sourced from the git tag;
72
+ Python 3.10–3.13 supported and exercised by a `tox` matrix.
73
+
74
+ ### Known limitations
75
+
76
+ - **`dft_type` supports `GGA` only.** `R2SCAN` and `MIXED` remain recognized names, but neither
77
+ can currently be fetched, for reasons upstream of this package; both now raise a `ValueError`
78
+ naming the cause before any network call rather than failing obscurely mid-fetch.
79
+ `R2SCAN` — the Materials Project stores the thermo type as the literal `r2SCAN` while
80
+ `emmet.core.thermo.ThermoType.R2SCAN` is `R2SCAN`; `mp_api` validates the argument against the
81
+ enum and forwards that casing, so the query matches nothing and the fetch comes back empty.
82
+ `MIXED` — pymatgen's `MaterialsProjectDFTMixingScheme` hashes entry ids, but new-API entries
83
+ carry `entry_id` as a dict, raising `TypeError: unhashable type: 'dict'`; past that, its
84
+ r2SCAN half would be empty for the reason above, making it silently GGA-only. The bundled data
85
+ corpus and every published result are built on `GGA`.
86
+ - **An empty Materials Project fetch now raises rather than being cached.** A zero-entry result
87
+ used to be written out as a 2-byte `[]`, which every later read then accepted as a warm cache.
88
+
89
+ [Unreleased]: https://github.com/willwerj/gliquid_python/compare/v0.1.0...HEAD
90
+ [0.1.0]: https://github.com/willwerj/gliquid_python/releases/tag/v0.1.0
@@ -0,0 +1,42 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it using the metadata below."
3
+ title: "GLiquid"
4
+ abstract: >-
5
+ A Python package for fitting DFT-referenced liquid free energies from digitized equilibrium
6
+ phase boundaries, and for interpolating multicomponent phase diagrams from the fitted binary
7
+ liquid descriptions.
8
+ type: software
9
+ # NOTE: this version is a literal and nothing derives it. The distribution version comes from
10
+ # the git tag via hatch-vcs, so this file and `date-released` below must be bumped BY HAND at
11
+ # each release -- see the release checklist in CONTRIBUTING.md.
12
+ version: "0.1.0"
13
+ date-released: "2026-08-12"
14
+ license: MIT
15
+ repository-code: "https://github.com/willwerj/gliquid_python"
16
+ url: "https://viz.whsunresearch.group/gliquid/interactive-matrix.html"
17
+ authors:
18
+ - given-names: Joshua
19
+ family-names: Willwerth
20
+ email: willwerj@umich.edu
21
+ affiliation: "University of Michigan"
22
+ - given-names: Abrar
23
+ family-names: Rauf
24
+ email: arauf@umich.edu
25
+ affiliation: "University of Michigan"
26
+ - given-names: Shibo
27
+ family-names: Tan
28
+ email: shibot@umich.edu
29
+ affiliation: "University of Michigan"
30
+ - given-names: Wenhao
31
+ family-names: Sun
32
+ email: whsun@umich.edu
33
+ affiliation: "University of Michigan"
34
+ keywords:
35
+ - "density functional theory"
36
+ - "thermodynamic modeling"
37
+ - "phase diagram"
38
+ - "liquidus"
39
+ - "solution phase"
40
+ - "intermetallic phase"
41
+ - "Materials Project"
42
+ - "Materials Platform for Data Science"
@@ -0,0 +1,130 @@
1
+ # Contributing to GLiquid
2
+
3
+ Pull requests are welcome. For anything larger than a bug fix, please open an issue first so
4
+ the change can be discussed before it is written.
5
+
6
+ ## Setup
7
+
8
+ Work from a clone, in an isolated environment. The convention among the maintainers is a conda
9
+ environment named `gliquidenv`:
10
+
11
+ ```bash
12
+ git clone https://github.com/willwerj/gliquid_python.git
13
+ cd gliquid_python
14
+ conda create --name gliquidenv python=3.10 # 3.11, 3.12 and 3.13 are also supported
15
+ conda activate gliquidenv
16
+ pip install -e .[test]
17
+ ```
18
+
19
+ `.[test]` adds `pytest` and `ruff` on top of the runtime dependencies. Add other extras as the
20
+ work needs them — `.[editor]` for `ConvexHullEditor`, `.[mpds]` for live MPDS downloads,
21
+ `.[notebook]` for local Jupyter, `.[models]` for the exact `scikit-learn`/`xgboost` versions the
22
+ serialized model artifacts were pickled against.
23
+
24
+ Working from a clone also means the data corpus resolves automatically: `gliquid.config` falls
25
+ back to the checkout's own `data/` directory when neither `set_data_dir()` nor
26
+ `GLIQUID_DATA_DIR` has been used. See the README for the full resolution order.
27
+
28
+ ## Running the tests
29
+
30
+ Run `pytest` from the repository root. The suite is tiered, and which tier you get depends on
31
+ what you pass:
32
+
33
+ ```bash
34
+ pytest # the public tests/ suite -- the default, and what a contributor runs
35
+ pytest tests_internal # the maintainer tier: value pins, figure goldens, gated families
36
+ pytest tests tests_internal # everything; this is what CI runs
37
+ ```
38
+
39
+ A bare `pytest` collects only `tests/` because `testpaths = ["tests"]` says so in
40
+ `pyproject.toml`; `tests_internal/` is tracked in git but never collected implicitly, and it is
41
+ excluded from the sdist.
42
+
43
+ For the fast edit/run loop, deselect the slow fits:
44
+
45
+ ```bash
46
+ pytest -m "not slow"
47
+ ```
48
+
49
+ That is roughly a 2.7x speedup on the public suite — measured at 84.7 s against 225.7 s for the
50
+ full run on a maintainer machine. It is a faster loop, not an instant one; run the full suite
51
+ before you push.
52
+
53
+ ### Markers
54
+
55
+ Four markers are declared, and `addopts = "--strict-markers"` means an undeclared or misspelled
56
+ one fails the run instead of silently applying no marker at all.
57
+
58
+ | marker | meaning |
59
+ | --- | --- |
60
+ | `pins` | A frozen-value characterization pin. It asserts that today's numbers equal the numbers captured when the pin was frozen. |
61
+ | `needs_cache` | Needs the workspace `matrix_data/` store of per-system DFT and digitized-diagram caches. **Skips**, rather than fails, on a checkout without it. |
62
+ | `needs_network` | Needs `NEW_MP_API_KEY` and a live Materials Project connection. |
63
+ | `slow` | A multi-second Nelder–Mead fit or hull build. Deselect with `-m "not slow"`. |
64
+
65
+ ### Re-freezing a pin
66
+
67
+ Every pin file's module docstring names the script that froze its fixture (the freezer scripts
68
+ live with the maintainers' driver scripts, outside this repository). Re-freezing is a deliberate
69
+ act: run that script, inspect the diff in the fixture JSON, and say in the commit message *why*
70
+ the values moved.
71
+
72
+ **Never edit a pin to make it pass.** A pin that changed is telling you the behavior changed. If
73
+ that change was intended, re-freeze it through the freezer and justify it. If it was not, you
74
+ have found the bug the pin exists to catch.
75
+
76
+ ## Formatting and linting
77
+
78
+ `ruff` is the formatter, configured in `pyproject.toml` at `line-length = 100` — not the 88
79
+ default, because this codebase already writes to roughly 95–100 characters and 88 would split
80
+ calls that read fine today.
81
+
82
+ ```bash
83
+ ruff format src/gliquid tests tests_internal # before you push
84
+ ruff format --check src/gliquid tests tests_internal
85
+ ruff check src/gliquid # advisory for now, not yet a gate
86
+ ```
87
+
88
+ Scattered `# noqa: WPS...` comments survive in the source. They are inherited from a retired
89
+ wemake-python-styleguide configuration and **are enforced by nothing today** — no tool in the
90
+ current setup reads them. Do not add new ones, and do not treat an existing one as evidence that
91
+ some rule is still active.
92
+
93
+ ## The print/logging boundary
94
+
95
+ The library reports through `logging` — one `logger = logging.getLogger(__name__)` per module,
96
+ all children of the `gliquid` logger — and installs no handlers and sets no levels of its own.
97
+ Handler and level configuration belongs to the application consuming the library, not to the
98
+ library.
99
+
100
+ Consequently, **a bare `print()` added anywhere in `src/gliquid` fails
101
+ `tests/test_logging_boundary.py`.** So does a direct `sys.stdout.write` / `sys.stderr.write`, and
102
+ so does any call to `basicConfig`, `addHandler`, `setLevel`, `StreamHandler`, `FileHandler` or
103
+ `NullHandler` inside the package. The scan is over the source tree, not the import graph, so a
104
+ `print()` on a branch no test happens to execute is still caught.
105
+
106
+ There are exactly two documented exemptions, listed in `EXEMPT` in that test file:
107
+
108
+ - `mpds.print_phase_mismatch_chart` — the function *is* a console chart renderer; the aligned
109
+ monospace rows are the product, not diagnostics.
110
+ - `hull_editor._log` — writes into an `ipywidgets` `Output` pane. Widget UI, not logging.
111
+
112
+ Adding a third exemption requires editing that test, which is the point. If your output is
113
+ diagnostic, use the module logger.
114
+
115
+ ## Release checklist
116
+
117
+ The distribution version is derived from the git tag by `hatch-vcs` — tagging is the release,
118
+ and no version literal lives in `src/`. `tests/test_version.py` enforces that.
119
+
120
+ 1. **Bump `CITATION.cff` by hand.** Its `version:` and `date-released:` are literals and nothing
121
+ derives them; this is the one file that must be edited at every release.
122
+ 2. **Add the `CHANGELOG.md` entry.** Move what is under `## [Unreleased]` into a new
123
+ `## [X.Y.Z] - YYYY-MM-DD` section and update the link definitions at the bottom.
124
+ 3. **Commit** those two changes.
125
+ 4. **Tag** the commit `vX.Y.Z` (SemVer, `v` prefix) and **push the tag**.
126
+
127
+ The release workflow does the rest — building the sdist and wheel from the tag and publishing
128
+ them. Do not hand-edit a version anywhere else; if the built artifact reports `0.0.x`, the
129
+ `hatch-vcs` fallback fired and the build did not see the tag. Investigate rather than
130
+ overriding it.
gliquid-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Joshua Willwerth
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.