GraphAtoms 2.3.2__tar.gz → 3.0.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 (96) hide show
  1. graphatoms-3.0.0/PKG-INFO +305 -0
  2. graphatoms-3.0.0/README.md +268 -0
  3. {graphatoms-2.3.2 → graphatoms-3.0.0}/pyproject.toml +31 -44
  4. {graphatoms-2.3.2 → graphatoms-3.0.0}/pyproject.toml.orig +36 -56
  5. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/dataclasses/_pydanticModel.py +1 -1
  6. graphatoms-3.0.0/src/graphatoms/geometry/__init__.py +23 -0
  7. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/geometry/_bond_list.py +1 -2
  8. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/geometry/_neighbor_list.py +6 -3
  9. graphatoms-3.0.0/src/graphatoms/geometry/itlee.py +599 -0
  10. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/bonds.py +59 -11
  11. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/graph.py +502 -6
  12. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/sysCluster.py +4 -1
  13. graphatoms-2.3.2/PKG-INFO +0 -185
  14. graphatoms-2.3.2/README.md +0 -143
  15. graphatoms-2.3.2/src/graphatoms/enterpoint/__init__.py +0 -0
  16. graphatoms-2.3.2/src/graphatoms/enterpoint/config/__init__.py +0 -116
  17. graphatoms-2.3.2/src/graphatoms/enterpoint/config/atoms/__init__.py +0 -24
  18. graphatoms-2.3.2/src/graphatoms/enterpoint/config/atoms/aseread.yaml +0 -5
  19. graphatoms-2.3.2/src/graphatoms/enterpoint/config/atoms/octahedron.yaml +0 -7
  20. graphatoms-2.3.2/src/graphatoms/enterpoint/config/bonds/__init__.py +0 -23
  21. graphatoms-2.3.2/src/graphatoms/enterpoint/config/bonds/raw.yaml +0 -8
  22. graphatoms-2.3.2/src/graphatoms/enterpoint/config/calculator/__init__.py +0 -29
  23. graphatoms-2.3.2/src/graphatoms/enterpoint/config/calculator/emt.yaml +0 -4
  24. graphatoms-2.3.2/src/graphatoms/enterpoint/config/calculator/nequip.yaml +0 -9
  25. graphatoms-2.3.2/src/graphatoms/enterpoint/config/example.yaml +0 -71
  26. graphatoms-2.3.2/src/graphatoms/enterpoint/config/run.yaml +0 -25
  27. graphatoms-2.3.2/src/graphatoms/enterpoint/network/__init__.py +0 -13
  28. graphatoms-2.3.2/src/graphatoms/enterpoint/network/_clsnetwork.py +0 -808
  29. graphatoms-2.3.2/src/graphatoms/enterpoint/network/_commands.py +0 -139
  30. graphatoms-2.3.2/src/graphatoms/enterpoint/network/_metadata.py +0 -369
  31. graphatoms-2.3.2/src/graphatoms/enterpoint/network/_recorder.py +0 -301
  32. graphatoms-2.3.2/src/graphatoms/enterpoint/network/_scheduler.py +0 -162
  33. graphatoms-2.3.2/src/graphatoms/enterpoint/parallel/__init__.py +0 -158
  34. graphatoms-2.3.2/src/graphatoms/enterpoint/parallel/_base.py +0 -133
  35. graphatoms-2.3.2/src/graphatoms/enterpoint/parallel/_dask.py +0 -47
  36. graphatoms-2.3.2/src/graphatoms/enterpoint/parallel/_executorlib.py +0 -48
  37. graphatoms-2.3.2/src/graphatoms/enterpoint/parallel/_ray.py +0 -98
  38. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/__init__.py +0 -39
  39. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/common/__init__.py +0 -21
  40. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/common/_base.py +0 -426
  41. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/common/_errors.py +0 -69
  42. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/common/_helper.py +0 -847
  43. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/general/__init__.py +0 -0
  44. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/general/_expl.py +0 -460
  45. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/general/otfkmc.py +0 -263
  46. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/general/rxngen.py +0 -151
  47. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/__init__.py +0 -0
  48. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/_helperv2.py +0 -427
  49. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/general/__init__.py +0 -0
  50. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/general/_expl.py +0 -160
  51. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/general/otfkmc.py +0 -16
  52. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/general/rxngen.py +0 -18
  53. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/ray/__init__.py +0 -0
  54. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/ray/_expl.py +0 -51
  55. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/ray/_helper.py +0 -183
  56. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/ray/otfkmc.py +0 -9
  57. graphatoms-2.3.2/src/graphatoms/enterpoint/runner/v2/ray/rxngen.py +0 -5
  58. graphatoms-2.3.2/src/graphatoms/geometry/__init__.py +0 -11
  59. graphatoms-2.3.2/src/graphatoms/reaction/__init__.py +0 -16
  60. graphatoms-2.3.2/src/graphatoms/reaction/_event.py +0 -632
  61. graphatoms-2.3.2/src/graphatoms/reaction/reaction.py +0 -48
  62. graphatoms-2.3.2/src/graphatoms/reaction/xxsorption.py +0 -214
  63. graphatoms-2.3.2/src/graphatoms/utils/adsorption.py +0 -794
  64. graphatoms-2.3.2/src/graphatoms/utils/aseqhull.py +0 -89
  65. graphatoms-2.3.2/src/graphatoms/utils/asetools.py +0 -420
  66. graphatoms-2.3.2/src/graphatoms/utils/logger.py +0 -69
  67. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/LICENSE +0 -0
  68. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/__init__.py +0 -0
  69. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/arrayapi/__init__.py +0 -0
  70. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/arrayapi/compat.py +0 -0
  71. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/arrayapi/typing.py +0 -0
  72. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/dataclasses/__init__.py +0 -0
  73. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/dataclasses/_numpydantic.py +0 -0
  74. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/dataclasses/_pydantic2pyarrow.py +0 -0
  75. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/dataclasses/_pydanticMixin.py +0 -0
  76. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/dataclasses/graph.py +0 -0
  77. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/geometry/_distance_pairs.py +0 -0
  78. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/geometry/_inner_outer.py +0 -0
  79. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/geometry/mic.py +0 -0
  80. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/geometry/rotation.py +0 -0
  81. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/geometry/sample.py +0 -0
  82. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/__init__.py +0 -0
  83. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/atoms.py +0 -0
  84. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/database/__init__.py +0 -0
  85. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/database/abc.py +0 -0
  86. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/database/dict.py +0 -0
  87. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/database/dir.py +0 -0
  88. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/database/hdf5.py +0 -0
  89. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/database/sqliteASE.py +0 -0
  90. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/sysGas.py +0 -0
  91. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/system/system.py +0 -0
  92. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/utils/__init__.py +0 -0
  93. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/utils/bytestool.py +0 -0
  94. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/utils/parser.py +0 -0
  95. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/utils/rdutils.py +0 -0
  96. {graphatoms-2.3.2 → graphatoms-3.0.0}/src/graphatoms/utils/subgraph.py +0 -0
@@ -0,0 +1,305 @@
1
+ Metadata-Version: 2.4
2
+ Name: graphatoms
3
+ Version: 3.0.0
4
+ Summary: The Chemical Core Class for Graph Theory Analysis.
5
+ Keywords: chemistry,graph theory,reaction,event,KMC
6
+ Author: LiuGaoyong
7
+ Author-email: LiuGaoyong <liugaoyong_88@163.com>
8
+ License-Expression: GPL-3.0-or-later
9
+ License-File: src/LICENSE
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
12
+ Classifier: Intended Audience :: Science/Research
13
+ Requires-Dist: ase
14
+ Requires-Dist: pymatgen>2023.6
15
+ Requires-Dist: rdkit>=2025
16
+ Requires-Dist: numpy>=2,<3
17
+ Requires-Dist: scipy>=1.10,<2
18
+ Requires-Dist: scikit-learn>=1.5
19
+ Requires-Dist: array-api-compat>=1.10
20
+ Requires-Dist: array-api-extra>=0.10
21
+ Requires-Dist: pyarrow
22
+ Requires-Dist: pandas
23
+ Requires-Dist: igraph>=0.11
24
+ Requires-Dist: h5py>=3.16
25
+ Requires-Dist: numpydantic
26
+ Requires-Dist: pydantic>=2.10
27
+ Requires-Dist: tomli ; python_full_version < '3.11'
28
+ Requires-Dist: tomli-w
29
+ Requires-Dist: pyyaml>=6.0
30
+ Requires-Dist: hydra-core>=1.1
31
+ Requires-Dist: typing-extensions
32
+ Requires-Python: >=3.12
33
+ Project-URL: Homepage, https://github.com/LiuGaoyong/GraphAtoms
34
+ Project-URL: Repository, https://github.com/LiuGaoyong/GraphAtoms
35
+ Project-URL: Issues, https://github.com/LiuGaoyong/GraphAtoms/issues/
36
+ Description-Content-Type: text/markdown
37
+
38
+ # graphatoms
39
+
40
+ [![Conda Version](https://img.shields.io/conda/vn/conda-forge/graphatoms.svg)](https://anaconda.org/conda-forge/graphatoms)
41
+ [![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/graphatoms.svg)](https://anaconda.org/conda-forge/graphatoms)
42
+ [![PyPI version](https://img.shields.io/pypi/v/graphatoms)](https://pypi.org/project/graphatoms/)
43
+ [![PyPI Downloads](https://static.pepy.tech/badge/graphatoms)](https://pepy.tech/projects/graphatoms)
44
+
45
+ The chemical core classes for graph-theory analysis of atomistic systems.
46
+
47
+ `graphatoms` represents extended systems, clusters and gas molecules as
48
+ coloured bond graphs. Everything is a frozen, validated
49
+ [Pydantic](https://docs.pydantic.dev/) model, so structures, energies and
50
+ graph metadata can be exchanged, stored and compared without losing type
51
+ safety.
52
+
53
+ > **Scope (v3)**: the application layer — CLI entry points, Hydra configs,
54
+ > reaction network generation, KMC runners and parallel executors — now lives
55
+ > in [RxNetGen](https://github.com/LiuGaoyong/RxNetGen). This package provides
56
+ > the reusable chemical core: `arrayapi`, `dataclasses`, `geometry`, `system`
57
+ > and `utils`.
58
+
59
+ ## Features
60
+
61
+ - **Validated graph models**: `SysGraph`, `System`, `Cluster` and `Gas` are
62
+ immutable Pydantic models with `numpydantic`-checked arrays.
63
+ - **Multi-format interoperability**: build from and export to ASE `Atoms`,
64
+ pymatgen `Structure`/`Molecule`, RDKit molecules, igraph graphs and plain
65
+ dictionaries.
66
+ - **Chemical graph analysis**: bond perception, neighbour lists, hop
67
+ distances, chordless cycles, connected components, Weisfeiler–Lehman
68
+ hashes, canonical keys (BLISS) and SMARTS extraction.
69
+ - **Structure matching**: pattern-to-system matching
70
+ (`BondGraph.get_match_mode`) and system-to-system equivalence via coloured
71
+ graph isomorphism or **ITLEE** — Invariant and Tolerant Local Environment
72
+ Equivalence (Williams, 2024).
73
+ - **Geometry tooling**: minimum image convention, rotation, sphere sampling
74
+ and distance/bond/neighbour construction.
75
+ - **Thermochemistry**: gas-phase enthalpy, entropy and free energy from
76
+ vibrational frequencies, plus minima/transition-state checks.
77
+ - **Persistent storage**: a uniform database interface with in-memory
78
+ (`dict`), folder, HDF5 and SQLite backends.
79
+ - **Array API compatibility**: backend-agnostic helpers that work with
80
+ NumPy, PyTorch, JAX, CuPy and other array-API-compliant libraries.
81
+
82
+ ## Installation
83
+
84
+ ```bash
85
+ pip install graphatoms
86
+ ```
87
+
88
+ With conda:
89
+
90
+ ```bash
91
+ conda install -c conda-forge graphatoms
92
+ ```
93
+
94
+ Python 3.12 or newer is required.
95
+
96
+ ## Quick start
97
+
98
+ ### A periodic system and a local cluster
99
+
100
+ ```python
101
+ import numpy as np
102
+ from ase.build import fcc111
103
+
104
+ from graphatoms.system import Cluster, System
105
+
106
+ atoms = fcc111("Pt", size=(3, 3, 4), vacuum=10.0)
107
+ system = System.from_ase(
108
+ atoms,
109
+ parse_bonds={"method": "raw"},
110
+ parse_atoms_is_outer_or_not=True, # detect surface atoms
111
+ )
112
+
113
+ print(system.formula, system.natoms, system.nbonds)
114
+ print(system.is_periodic, system.idx_outer)
115
+
116
+ # Grow a movable cluster around atom 0; atoms farther than `env_threshold`
117
+ # are fixed, and atoms closer than `max_moved_threshold` may move.
118
+ cluster = Cluster.from_select(
119
+ system,
120
+ core=np.array([0]),
121
+ method="hop",
122
+ max_moved_threshold=1,
123
+ env_threshold=2,
124
+ )
125
+ print(cluster.ncore, cluster.nmoved, cluster.nfix)
126
+ ```
127
+
128
+ ### A gas molecule
129
+
130
+ ```python
131
+ import numpy as np
132
+
133
+ from graphatoms.system import Gas
134
+
135
+ gas = Gas.from_name("CH4", sticking=1.0)
136
+ gas = gas.update_energetics(
137
+ energy=-0.5,
138
+ fmax=0.02,
139
+ frequencies=np.array(
140
+ [1300.0, 1300.0, 1300.0, 1500.0, 1500.0, 1500.0, 2900.0, 2900.0, 2900.0]
141
+ ),
142
+ )
143
+
144
+ print(gas.formula, gas.natoms)
145
+ print(gas.get_enthalpy(temp=300.0))
146
+ print(gas.get_free_energy(temp=300.0))
147
+ ```
148
+
149
+ ### Equivalence checks
150
+
151
+ ```python
152
+ # `other` is another SysGraph with the same number of atoms.
153
+ same_topology = system.is_equivalent(other, method="graph")
154
+ same_geometry = system.is_equivalent(
155
+ other,
156
+ method="itlee",
157
+ tolerance=0.1, # L2 tolerance in Å
158
+ fields=("numbers", "is_fix"),
159
+ )
160
+ ```
161
+
162
+ `method="graph"` compares the coloured bond graph (hash bucket first, then
163
+ igraph isomorphism). `method="itlee"` compares equal-sized coloured point
164
+ clouds under rotation, translation and atom permutation. For
165
+ pattern-to-system queries, use `BondGraph.get_match_mode`.
166
+
167
+ ### Storage
168
+
169
+ ```python
170
+ from pathlib import Path
171
+
172
+ from graphatoms.system import SysGraph
173
+ from graphatoms.system.database import get_db
174
+
175
+ db = get_db(format="hdf5", path=Path("systems.h5"))
176
+ db.add(SysGraph.from_ase(atoms, parse_bonds={"method": "raw"}))
177
+
178
+ for key in db:
179
+ stored = SysGraph.from_ase(db[key], parse_bonds=None)
180
+ print(key, stored.formula)
181
+ ```
182
+
183
+ Supported formats: `dict` (default), `folder`/`dir`, `hdf5`/`h5`, `sqlite`.
184
+ Records are stored as ASE `Atoms`; rebuild a graph from a record with
185
+ `SysGraph.from_ase()`.
186
+
187
+ ## Module structure
188
+
189
+ ```
190
+ src/graphatoms/
191
+ ├── arrayapi/ # array-API namespace resolution and typing
192
+ ├── dataclasses/ # Pydantic/numpydantic base models, PyArrow schemas
193
+ ├── geometry/ # bond_list, neighbor_list, distance_pairs,
194
+ │ # mic, rotation, sample, itlee
195
+ ├── system/ # core classes
196
+ │ ├── atoms.py # Box, Energetics, Matter, Structure
197
+ │ ├── bonds.py # BondGraph: graph metrics, hashes, matching
198
+ │ ├── graph.py # SysGraph: structure + bonds + atom tags
199
+ │ ├── system.py # System: full periodic/extended systems
200
+ │ ├── sysCluster.py # Cluster: movable/fixed regions around a site
201
+ │ ├── sysGas.py # Gas: ideal-gas thermochemistry
202
+ │ └── database/ # dict, folder, HDF5, SQLite backends
203
+ └── utils/ # bytestool, parser (Hydra), rdutils, subgraph
204
+ ```
205
+
206
+ The public objects live in their submodules rather than the package root:
207
+
208
+ ```python
209
+ from graphatoms.system import SysGraph, System, Cluster, Gas
210
+ from graphatoms.system.database import get_db
211
+ from graphatoms.geometry import bond_list, neighbor_list, distance_pairs
212
+ ```
213
+
214
+ ## Data model
215
+
216
+ `SysGraph` combines four mixins:
217
+
218
+ | Mixin | Contents |
219
+ | ----------- | --------------------------------------------------------------- |
220
+ | `Structure` | `numbers`, `positions`, `cell`/`pbc`, plus `Energetics` |
221
+ | `BondGraph` | bond `pair`, `shift`, `order`, `coordination`, derived `P`/`CN` |
222
+ | `AtomTag` | boolean tags `is_adsorbate`, `is_outer`, `is_core`, `is_fix` |
223
+ | `GasMixin` | `sticking` coefficient and the derived `is_gas` flag |
224
+
225
+ `System` is a `SysGraph` for the full system, `Cluster` is a selected,
226
+ possibly partially fixed region of it, and `Gas` adds a `sticking`
227
+ coefficient and ideal-gas thermodynamics. All of them accept
228
+ `from_ase()`, `to_ase()`, `from_dict()`/`to_dict()`, `from_igraph()`/
229
+ `to_igraph()` and, where meaningful, pymatgen/RDKit conversions.
230
+
231
+ ## Requirements
232
+
233
+ Runtime dependencies:
234
+
235
+ - Python >= 3.12
236
+ - ase
237
+ - pymatgen > 2023.6
238
+ - rdkit >= 2025
239
+ - numpy >= 2, < 3
240
+ - scipy >= 1.10
241
+ - scikit-learn >= 1.5
242
+ - array-api-compat >= 1.10
243
+ - array-api-extra >= 0.10
244
+ - pyarrow
245
+ - pandas
246
+ - igraph >= 0.11
247
+ - h5py >= 3.16
248
+ - numpydantic
249
+ - pydantic >= 2.10
250
+ - hydra-core >= 1.1
251
+ - pyyaml >= 6.0
252
+ - tomli-w
253
+ - typing-extensions
254
+
255
+ ## Development
256
+
257
+ The project is managed with [pixi](https://pixi.sh/) (or `uv`):
258
+
259
+ ```bash
260
+ pixi install
261
+ pixi run test # pytest -s -vv
262
+ pixi run benchmark # benchmark suite
263
+ ```
264
+
265
+ With `uv`:
266
+
267
+ ```bash
268
+ uv sync
269
+ uv run pytest src/tests/ -v
270
+ uv run pytest src/tests-benchmark/ -v
271
+ ```
272
+
273
+ Lint and format with Ruff:
274
+
275
+ ```bash
276
+ ruff check .
277
+ ruff format .
278
+ ```
279
+
280
+ ## Array API compatibility
281
+
282
+ `graphatoms.arrayapi` resolves the active array namespace, and
283
+ `graphatoms.utils.subgraph` implements backend-agnostic graph helpers:
284
+
285
+ - `subgraph()` — extract an induced subgraph from edge indices
286
+ - `map_index()` — map indices to positions in a reference index array
287
+ - `index_to_mask()` — convert indices to a boolean mask
288
+ - `maybe_num_nodes()` — infer the node count from edge indices
289
+
290
+ These functions only use Array API standard operations, so the same code runs
291
+ on NumPy, PyTorch and JAX arrays.
292
+
293
+ ## License
294
+
295
+ GPL-3.0-or-later
296
+
297
+ ## Authors
298
+
299
+ - LiuGaoyong (liugaoyong_88@163.com)
300
+
301
+ ## Links
302
+
303
+ - Homepage: https://github.com/LiuGaoyong/GraphAtoms
304
+ - Repository: https://github.com/LiuGaoyong/GraphAtoms
305
+ - Issues: https://github.com/LiuGaoyong/GraphAtoms/issues/
@@ -0,0 +1,268 @@
1
+ # graphatoms
2
+
3
+ [![Conda Version](https://img.shields.io/conda/vn/conda-forge/graphatoms.svg)](https://anaconda.org/conda-forge/graphatoms)
4
+ [![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/graphatoms.svg)](https://anaconda.org/conda-forge/graphatoms)
5
+ [![PyPI version](https://img.shields.io/pypi/v/graphatoms)](https://pypi.org/project/graphatoms/)
6
+ [![PyPI Downloads](https://static.pepy.tech/badge/graphatoms)](https://pepy.tech/projects/graphatoms)
7
+
8
+ The chemical core classes for graph-theory analysis of atomistic systems.
9
+
10
+ `graphatoms` represents extended systems, clusters and gas molecules as
11
+ coloured bond graphs. Everything is a frozen, validated
12
+ [Pydantic](https://docs.pydantic.dev/) model, so structures, energies and
13
+ graph metadata can be exchanged, stored and compared without losing type
14
+ safety.
15
+
16
+ > **Scope (v3)**: the application layer — CLI entry points, Hydra configs,
17
+ > reaction network generation, KMC runners and parallel executors — now lives
18
+ > in [RxNetGen](https://github.com/LiuGaoyong/RxNetGen). This package provides
19
+ > the reusable chemical core: `arrayapi`, `dataclasses`, `geometry`, `system`
20
+ > and `utils`.
21
+
22
+ ## Features
23
+
24
+ - **Validated graph models**: `SysGraph`, `System`, `Cluster` and `Gas` are
25
+ immutable Pydantic models with `numpydantic`-checked arrays.
26
+ - **Multi-format interoperability**: build from and export to ASE `Atoms`,
27
+ pymatgen `Structure`/`Molecule`, RDKit molecules, igraph graphs and plain
28
+ dictionaries.
29
+ - **Chemical graph analysis**: bond perception, neighbour lists, hop
30
+ distances, chordless cycles, connected components, Weisfeiler–Lehman
31
+ hashes, canonical keys (BLISS) and SMARTS extraction.
32
+ - **Structure matching**: pattern-to-system matching
33
+ (`BondGraph.get_match_mode`) and system-to-system equivalence via coloured
34
+ graph isomorphism or **ITLEE** — Invariant and Tolerant Local Environment
35
+ Equivalence (Williams, 2024).
36
+ - **Geometry tooling**: minimum image convention, rotation, sphere sampling
37
+ and distance/bond/neighbour construction.
38
+ - **Thermochemistry**: gas-phase enthalpy, entropy and free energy from
39
+ vibrational frequencies, plus minima/transition-state checks.
40
+ - **Persistent storage**: a uniform database interface with in-memory
41
+ (`dict`), folder, HDF5 and SQLite backends.
42
+ - **Array API compatibility**: backend-agnostic helpers that work with
43
+ NumPy, PyTorch, JAX, CuPy and other array-API-compliant libraries.
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ pip install graphatoms
49
+ ```
50
+
51
+ With conda:
52
+
53
+ ```bash
54
+ conda install -c conda-forge graphatoms
55
+ ```
56
+
57
+ Python 3.12 or newer is required.
58
+
59
+ ## Quick start
60
+
61
+ ### A periodic system and a local cluster
62
+
63
+ ```python
64
+ import numpy as np
65
+ from ase.build import fcc111
66
+
67
+ from graphatoms.system import Cluster, System
68
+
69
+ atoms = fcc111("Pt", size=(3, 3, 4), vacuum=10.0)
70
+ system = System.from_ase(
71
+ atoms,
72
+ parse_bonds={"method": "raw"},
73
+ parse_atoms_is_outer_or_not=True, # detect surface atoms
74
+ )
75
+
76
+ print(system.formula, system.natoms, system.nbonds)
77
+ print(system.is_periodic, system.idx_outer)
78
+
79
+ # Grow a movable cluster around atom 0; atoms farther than `env_threshold`
80
+ # are fixed, and atoms closer than `max_moved_threshold` may move.
81
+ cluster = Cluster.from_select(
82
+ system,
83
+ core=np.array([0]),
84
+ method="hop",
85
+ max_moved_threshold=1,
86
+ env_threshold=2,
87
+ )
88
+ print(cluster.ncore, cluster.nmoved, cluster.nfix)
89
+ ```
90
+
91
+ ### A gas molecule
92
+
93
+ ```python
94
+ import numpy as np
95
+
96
+ from graphatoms.system import Gas
97
+
98
+ gas = Gas.from_name("CH4", sticking=1.0)
99
+ gas = gas.update_energetics(
100
+ energy=-0.5,
101
+ fmax=0.02,
102
+ frequencies=np.array(
103
+ [1300.0, 1300.0, 1300.0, 1500.0, 1500.0, 1500.0, 2900.0, 2900.0, 2900.0]
104
+ ),
105
+ )
106
+
107
+ print(gas.formula, gas.natoms)
108
+ print(gas.get_enthalpy(temp=300.0))
109
+ print(gas.get_free_energy(temp=300.0))
110
+ ```
111
+
112
+ ### Equivalence checks
113
+
114
+ ```python
115
+ # `other` is another SysGraph with the same number of atoms.
116
+ same_topology = system.is_equivalent(other, method="graph")
117
+ same_geometry = system.is_equivalent(
118
+ other,
119
+ method="itlee",
120
+ tolerance=0.1, # L2 tolerance in Å
121
+ fields=("numbers", "is_fix"),
122
+ )
123
+ ```
124
+
125
+ `method="graph"` compares the coloured bond graph (hash bucket first, then
126
+ igraph isomorphism). `method="itlee"` compares equal-sized coloured point
127
+ clouds under rotation, translation and atom permutation. For
128
+ pattern-to-system queries, use `BondGraph.get_match_mode`.
129
+
130
+ ### Storage
131
+
132
+ ```python
133
+ from pathlib import Path
134
+
135
+ from graphatoms.system import SysGraph
136
+ from graphatoms.system.database import get_db
137
+
138
+ db = get_db(format="hdf5", path=Path("systems.h5"))
139
+ db.add(SysGraph.from_ase(atoms, parse_bonds={"method": "raw"}))
140
+
141
+ for key in db:
142
+ stored = SysGraph.from_ase(db[key], parse_bonds=None)
143
+ print(key, stored.formula)
144
+ ```
145
+
146
+ Supported formats: `dict` (default), `folder`/`dir`, `hdf5`/`h5`, `sqlite`.
147
+ Records are stored as ASE `Atoms`; rebuild a graph from a record with
148
+ `SysGraph.from_ase()`.
149
+
150
+ ## Module structure
151
+
152
+ ```
153
+ src/graphatoms/
154
+ ├── arrayapi/ # array-API namespace resolution and typing
155
+ ├── dataclasses/ # Pydantic/numpydantic base models, PyArrow schemas
156
+ ├── geometry/ # bond_list, neighbor_list, distance_pairs,
157
+ │ # mic, rotation, sample, itlee
158
+ ├── system/ # core classes
159
+ │ ├── atoms.py # Box, Energetics, Matter, Structure
160
+ │ ├── bonds.py # BondGraph: graph metrics, hashes, matching
161
+ │ ├── graph.py # SysGraph: structure + bonds + atom tags
162
+ │ ├── system.py # System: full periodic/extended systems
163
+ │ ├── sysCluster.py # Cluster: movable/fixed regions around a site
164
+ │ ├── sysGas.py # Gas: ideal-gas thermochemistry
165
+ │ └── database/ # dict, folder, HDF5, SQLite backends
166
+ └── utils/ # bytestool, parser (Hydra), rdutils, subgraph
167
+ ```
168
+
169
+ The public objects live in their submodules rather than the package root:
170
+
171
+ ```python
172
+ from graphatoms.system import SysGraph, System, Cluster, Gas
173
+ from graphatoms.system.database import get_db
174
+ from graphatoms.geometry import bond_list, neighbor_list, distance_pairs
175
+ ```
176
+
177
+ ## Data model
178
+
179
+ `SysGraph` combines four mixins:
180
+
181
+ | Mixin | Contents |
182
+ | ----------- | --------------------------------------------------------------- |
183
+ | `Structure` | `numbers`, `positions`, `cell`/`pbc`, plus `Energetics` |
184
+ | `BondGraph` | bond `pair`, `shift`, `order`, `coordination`, derived `P`/`CN` |
185
+ | `AtomTag` | boolean tags `is_adsorbate`, `is_outer`, `is_core`, `is_fix` |
186
+ | `GasMixin` | `sticking` coefficient and the derived `is_gas` flag |
187
+
188
+ `System` is a `SysGraph` for the full system, `Cluster` is a selected,
189
+ possibly partially fixed region of it, and `Gas` adds a `sticking`
190
+ coefficient and ideal-gas thermodynamics. All of them accept
191
+ `from_ase()`, `to_ase()`, `from_dict()`/`to_dict()`, `from_igraph()`/
192
+ `to_igraph()` and, where meaningful, pymatgen/RDKit conversions.
193
+
194
+ ## Requirements
195
+
196
+ Runtime dependencies:
197
+
198
+ - Python >= 3.12
199
+ - ase
200
+ - pymatgen > 2023.6
201
+ - rdkit >= 2025
202
+ - numpy >= 2, < 3
203
+ - scipy >= 1.10
204
+ - scikit-learn >= 1.5
205
+ - array-api-compat >= 1.10
206
+ - array-api-extra >= 0.10
207
+ - pyarrow
208
+ - pandas
209
+ - igraph >= 0.11
210
+ - h5py >= 3.16
211
+ - numpydantic
212
+ - pydantic >= 2.10
213
+ - hydra-core >= 1.1
214
+ - pyyaml >= 6.0
215
+ - tomli-w
216
+ - typing-extensions
217
+
218
+ ## Development
219
+
220
+ The project is managed with [pixi](https://pixi.sh/) (or `uv`):
221
+
222
+ ```bash
223
+ pixi install
224
+ pixi run test # pytest -s -vv
225
+ pixi run benchmark # benchmark suite
226
+ ```
227
+
228
+ With `uv`:
229
+
230
+ ```bash
231
+ uv sync
232
+ uv run pytest src/tests/ -v
233
+ uv run pytest src/tests-benchmark/ -v
234
+ ```
235
+
236
+ Lint and format with Ruff:
237
+
238
+ ```bash
239
+ ruff check .
240
+ ruff format .
241
+ ```
242
+
243
+ ## Array API compatibility
244
+
245
+ `graphatoms.arrayapi` resolves the active array namespace, and
246
+ `graphatoms.utils.subgraph` implements backend-agnostic graph helpers:
247
+
248
+ - `subgraph()` — extract an induced subgraph from edge indices
249
+ - `map_index()` — map indices to positions in a reference index array
250
+ - `index_to_mask()` — convert indices to a boolean mask
251
+ - `maybe_num_nodes()` — infer the node count from edge indices
252
+
253
+ These functions only use Array API standard operations, so the same code runs
254
+ on NumPy, PyTorch and JAX arrays.
255
+
256
+ ## License
257
+
258
+ GPL-3.0-or-later
259
+
260
+ ## Authors
261
+
262
+ - LiuGaoyong (liugaoyong_88@163.com)
263
+
264
+ ## Links
265
+
266
+ - Homepage: https://github.com/LiuGaoyong/GraphAtoms
267
+ - Repository: https://github.com/LiuGaoyong/GraphAtoms
268
+ - Issues: https://github.com/LiuGaoyong/GraphAtoms/issues/
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "graphatoms"
7
- version = "2.3.2"
7
+ version = "3.0.0"
8
8
  readme = "README.md"
9
9
  description = "The Chemical Core Class for Graph Theory Analysis."
10
10
  license-files = ["src/LICENSE"]
@@ -27,26 +27,21 @@ dependencies = [
27
27
  "pymatgen>2023.6",
28
28
  "rdkit>=2025",
29
29
  "numpy>=2,<3",
30
- "pandas>=2,<4",
31
30
  "scipy>=1.10,<2",
32
31
  "scikit-learn>=1.5",
33
32
  "array-api-compat>=1.10",
34
33
  "array_api-extra>=0.10",
35
34
  "pyarrow",
35
+ "pandas",
36
36
  "igraph>=0.11",
37
37
  "h5py>=3.16",
38
38
  "numpydantic",
39
- "ovld",
40
39
  "pydantic>=2.10",
41
- "python-snappy>=0.7.3",
42
40
  "tomli; python_version < '3.11'",
43
41
  "tomli-w",
42
+ "pyyaml>=6.0",
43
+ "hydra-core>=1.1",
44
44
  "typing-extensions",
45
- "joblib",
46
- "executorlib",
47
- "hydra-core",
48
- "typer",
49
- "loguru",
50
45
  ]
51
46
 
52
47
  [project.urls]
@@ -54,11 +49,6 @@ Homepage = "https://github.com/LiuGaoyong/GraphAtoms"
54
49
  Repository = "https://github.com/LiuGaoyong/GraphAtoms"
55
50
  Issues = "https://github.com/LiuGaoyong/GraphAtoms/issues/"
56
51
 
57
- [project.scripts]
58
- graphatoms-config = "graphatoms.enterpoint.config:print_config"
59
- graphatoms-network = "graphatoms.enterpoint.network:main"
60
- graphatoms-run = "graphatoms.enterpoint.runner:run"
61
-
62
52
  [[project.authors]]
63
53
  name = "LiuGaoyong"
64
54
  email = "liugaoyong_88@163.com"
@@ -66,22 +56,20 @@ email = "liugaoyong_88@163.com"
66
56
  [dependency-groups]
67
57
  dev = [
68
58
  "ruff>=0.11",
69
- "openbabel-wheel",
59
+ "python-snappy>=0.7.3",
70
60
  "array-api-strict",
71
61
  "pytest>=8.3",
72
62
  "pytest-xdist",
73
63
  "jupyterlab",
74
64
  "chemiscope",
75
65
  "nglview",
76
- "grpcio",
77
- "ray",
78
66
  ]
79
67
 
80
68
  [tool.uv]
81
69
  package = true
82
70
 
83
71
  [[tool.uv.index]]
84
- url = "https://mirrors.nju.edu.cn/pypi/web/simple"
72
+ url = "https://mirrors.cernet.edu.cn/pypi/web/simple"
85
73
  default = true
86
74
 
87
75
  [tool.pytest.ini_options]
@@ -146,29 +134,28 @@ benchmark = "pytest -s src/tests-benchmark/*.py"
146
134
 
147
135
  [tool.pixi.dependencies]
148
136
  python = ">=3.12"
149
- pytest = ">=9.0.3,<10"
150
- array-api-compat = ">=1.15.0,<2"
151
- array-api-extra = ">=0.11.0,<0.12"
152
- array-api-strict = ">=2.5,<3"
153
- ase = ">=3.28.0,<4"
154
- pymatgen = ">=2026.5.4,<2027"
155
- rdkit = ">=2025.9.5,<2027"
156
- openbabel = ">=3.1.1,<4"
157
- pyarrow = ">=21.0.0,<25"
158
- scikit-learn = ">=1.8.0,<2"
159
- python-igraph = ">=0.11.9,<0.12"
160
- numpy = ">=2.0.0,<3"
161
- pydantic = ">=2.10.0,<3"
162
- numpydantic = ">=1.8.1,<2"
163
- python-snappy = ">=0.7.3,<0.8"
164
- h5py = ">=3.16.0,<4"
165
- hydra-core = ">=1.3.2,<2"
166
- tomli-w = ">=1.2.0,<2"
167
- loguru = ">=0.7.3,<0.8"
168
- jupyterlab = ">=4.5.8,<5"
169
- joblib = ">=1.1.0,<2"
170
- ovld = ">=0.5.15,<0.6"
171
- pytest-xdist = ">=3.8.0,<4"
172
- executorlib = ">=1.8,<2"
173
- typer = ">=0.20,<1"
174
- grpcio = ">=1.52.0,<2"
137
+ pytest = ">=8"
138
+ array-api-compat = ">=1.15.0"
139
+ array-api-extra = ">=0.11.0"
140
+ array-api-strict = ">=2.5"
141
+ ase = ">=3.28.0"
142
+ pymatgen = ">=2026.5.4"
143
+ rdkit = ">=2025.9.5"
144
+ openbabel = ">=3.1.1"
145
+ pyarrow = ">=21.0.0"
146
+ scikit-learn = ">=1.8.0"
147
+ python-igraph = ">=0.11.9"
148
+ numpy = ">=2.0.0"
149
+ pydantic = ">=2.10.0"
150
+ numpydantic = ">=1.8.1"
151
+ python-snappy = ">=0.7.3"
152
+ h5py = ">=3.16"
153
+ tomli-w = ">=1.2.0"
154
+ jupyterlab = ">=4.5.8"
155
+ pytest-xdist = ">=3.8.0"
156
+ nglview = ">=0.14.0"
157
+ ruff = ">=0.11"
158
+ chemiscope = ">=0.1.0"
159
+ pyyaml = ">=6.0"
160
+ hydra-core = ">=1.1"
161
+ typing-extensions = ">=4.12.0"