xnns 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 (148) hide show
  1. xnns-0.1.0/LICENSE +21 -0
  2. xnns-0.1.0/PKG-INFO +422 -0
  3. xnns-0.1.0/README.md +332 -0
  4. xnns-0.1.0/pyproject.toml +148 -0
  5. xnns-0.1.0/setup.cfg +4 -0
  6. xnns-0.1.0/src/xnn/__init__.py +52 -0
  7. xnns-0.1.0/src/xnn/__main__.py +10 -0
  8. xnns-0.1.0/src/xnn/cnn/__init__.py +4 -0
  9. xnns-0.1.0/src/xnn/cnn/models/__init__.py +3 -0
  10. xnns-0.1.0/src/xnn/cnn/models/schnet.py +472 -0
  11. xnns-0.1.0/src/xnn/common/__init__.py +11 -0
  12. xnns-0.1.0/src/xnn/common/_torch_compat.py +39 -0
  13. xnns-0.1.0/src/xnn/common/benchmark/__init__.py +46 -0
  14. xnns-0.1.0/src/xnn/common/benchmark/config.py +447 -0
  15. xnns-0.1.0/src/xnn/common/benchmark/energy.py +184 -0
  16. xnns-0.1.0/src/xnn/common/benchmark/metrics.py +268 -0
  17. xnns-0.1.0/src/xnn/common/benchmark/report.py +321 -0
  18. xnns-0.1.0/src/xnn/common/benchmark/runner.py +311 -0
  19. xnns-0.1.0/src/xnn/common/cli/__init__.py +3 -0
  20. xnns-0.1.0/src/xnn/common/cli/main.py +162 -0
  21. xnns-0.1.0/src/xnn/common/config/__init__.py +11 -0
  22. xnns-0.1.0/src/xnn/common/config/coerce.py +155 -0
  23. xnns-0.1.0/src/xnn/common/config/loaders.py +186 -0
  24. xnns-0.1.0/src/xnn/common/config/schema.py +204 -0
  25. xnns-0.1.0/src/xnn/common/config/translate.py +197 -0
  26. xnns-0.1.0/src/xnn/common/data/__init__.py +11 -0
  27. xnns-0.1.0/src/xnn/common/data/ase_io.py +129 -0
  28. xnns-0.1.0/src/xnn/common/data/atomic_data.py +173 -0
  29. xnns-0.1.0/src/xnn/common/data/dataset.py +273 -0
  30. xnns-0.1.0/src/xnn/common/data/hub/__init__.py +45 -0
  31. xnns-0.1.0/src/xnn/common/data/hub/_download.py +177 -0
  32. xnns-0.1.0/src/xnn/common/data/hub/ani1.py +233 -0
  33. xnns-0.1.0/src/xnn/common/data/hub/ani1ccx.py +106 -0
  34. xnns-0.1.0/src/xnn/common/data/hub/ani1x.py +224 -0
  35. xnns-0.1.0/src/xnn/common/data/hub/ani2x.py +233 -0
  36. xnns-0.1.0/src/xnn/common/data/hub/argon_md.py +108 -0
  37. xnns-0.1.0/src/xnn/common/data/hub/base.py +176 -0
  38. xnns-0.1.0/src/xnn/common/data/hub/lode_dimers.py +255 -0
  39. xnns-0.1.0/src/xnn/common/data/hub/rmd17.py +248 -0
  40. xnns-0.1.0/src/xnn/common/data/neighborlist.py +227 -0
  41. xnns-0.1.0/src/xnn/common/deploy/__init__.py +16 -0
  42. xnns-0.1.0/src/xnn/common/deploy/ase_calculator.py +126 -0
  43. xnns-0.1.0/src/xnn/common/deploy/lammps.py +166 -0
  44. xnns-0.1.0/src/xnn/common/deploy/mdi_engine.py +446 -0
  45. xnns-0.1.0/src/xnn/common/deploy/torchscript.py +558 -0
  46. xnns-0.1.0/src/xnn/common/featurizers/__init__.py +6 -0
  47. xnns-0.1.0/src/xnn/common/featurizers/base.py +75 -0
  48. xnns-0.1.0/src/xnn/common/featurizers/cutoff.py +41 -0
  49. xnns-0.1.0/src/xnn/common/featurizers/radial.py +59 -0
  50. xnns-0.1.0/src/xnn/common/models/__init__.py +17 -0
  51. xnns-0.1.0/src/xnn/common/models/base.py +112 -0
  52. xnns-0.1.0/src/xnn/common/models/les.py +384 -0
  53. xnns-0.1.0/src/xnn/common/models/ops.py +135 -0
  54. xnns-0.1.0/src/xnn/common/models/outputs.py +148 -0
  55. xnns-0.1.0/src/xnn/common/models/registry.py +120 -0
  56. xnns-0.1.0/src/xnn/common/train/__init__.py +4 -0
  57. xnns-0.1.0/src/xnn/common/train/losses.py +76 -0
  58. xnns-0.1.0/src/xnn/common/train/trainer.py +450 -0
  59. xnns-0.1.0/src/xnn/dnn/__init__.py +4 -0
  60. xnns-0.1.0/src/xnn/dnn/featurizers/__init__.py +6 -0
  61. xnns-0.1.0/src/xnn/dnn/featurizers/aev.py +221 -0
  62. xnns-0.1.0/src/xnn/dnn/featurizers/symmetry_functions.py +251 -0
  63. xnns-0.1.0/src/xnn/dnn/models/__init__.py +6 -0
  64. xnns-0.1.0/src/xnn/dnn/models/ani.py +353 -0
  65. xnns-0.1.0/src/xnn/dnn/models/base.py +224 -0
  66. xnns-0.1.0/src/xnn/dnn/models/d3.py +236 -0
  67. xnns-0.1.0/src/xnn/dnn/models/d3_tables.npz +0 -0
  68. xnns-0.1.0/src/xnn/dnn/models/hdnnp.py +68 -0
  69. xnns-0.1.0/src/xnn/dnn/models/physnet.py +615 -0
  70. xnns-0.1.0/src/xnn/ffnn/__init__.py +25 -0
  71. xnns-0.1.0/src/xnn/ffnn/common/__init__.py +29 -0
  72. xnns-0.1.0/src/xnn/ffnn/common/elements.py +37 -0
  73. xnns-0.1.0/src/xnn/ffnn/common/frc.py +1583 -0
  74. xnns-0.1.0/src/xnn/ffnn/common/typing.py +237 -0
  75. xnns-0.1.0/src/xnn/ffnn/data/LICENSE-SEAMM +29 -0
  76. xnns-0.1.0/src/xnn/ffnn/data/README.md +65 -0
  77. xnns-0.1.0/src/xnn/ffnn/data/lopls.frc +161 -0
  78. xnns-0.1.0/src/xnn/ffnn/data/oplsaa.frc +11726 -0
  79. xnns-0.1.0/src/xnn/ffnn/data/oplsaa_1996.frc +57 -0
  80. xnns-0.1.0/src/xnn/ffnn/data/reaxff/CHLiOFSi_Yun_2017.frc +322 -0
  81. xnns-0.1.0/src/xnn/ffnn/data/reaxff/CHNOFSClNiPt_FC_2013.frc +461 -0
  82. xnns-0.1.0/src/xnn/ffnn/data/reaxff/CHNO_HNS_2014.frc +272 -0
  83. xnns-0.1.0/src/xnn/ffnn/data/reaxff/CHNO_RDX_2003.frc +270 -0
  84. xnns-0.1.0/src/xnn/ffnn/data/reaxff/CHOFe_FeOH_2010.frc +265 -0
  85. xnns-0.1.0/src/xnn/ffnn/data/reaxff/CHOV_VOH_2008.frc +270 -0
  86. xnns-0.1.0/src/xnn/ffnn/data/reaxff/CHO_cho_2008.frc +227 -0
  87. xnns-0.1.0/src/xnn/ffnn/data/reaxff/CH_2018.frc +162 -0
  88. xnns-0.1.0/src/xnn/ffnn/data/reaxff/CLiSi_Guifo_2023.frc +185 -0
  89. xnns-0.1.0/src/xnn/ffnn/data/reaxff/HBNO_AB_2010.frc +253 -0
  90. xnns-0.1.0/src/xnn/ffnn/data/reaxff/HOAu_AuO_2010.frc +223 -0
  91. xnns-0.1.0/src/xnn/ffnn/data/reaxff/HOZn_ZNOH_2010.frc +199 -0
  92. xnns-0.1.0/src/xnn/ffnn/models/__init__.py +11 -0
  93. xnns-0.1.0/src/xnn/ffnn/models/ffield.py +1093 -0
  94. xnns-0.1.0/src/xnn/ffnn/models/opls.py +980 -0
  95. xnns-0.1.0/src/xnn/ffnn/models/oplslib.py +632 -0
  96. xnns-0.1.0/src/xnn/ffnn/models/reaxff.py +1729 -0
  97. xnns-0.1.0/src/xnn/ffnn/models/topology.py +403 -0
  98. xnns-0.1.0/src/xnn/gnn/__init__.py +4 -0
  99. xnns-0.1.0/src/xnn/gnn/featurizers/__init__.py +7 -0
  100. xnns-0.1.0/src/xnn/gnn/featurizers/cartesian.py +152 -0
  101. xnns-0.1.0/src/xnn/gnn/featurizers/cutoff.py +52 -0
  102. xnns-0.1.0/src/xnn/gnn/featurizers/radial.py +71 -0
  103. xnns-0.1.0/src/xnn/gnn/featurizers/spherical.py +173 -0
  104. xnns-0.1.0/src/xnn/gnn/models/__init__.py +7 -0
  105. xnns-0.1.0/src/xnn/gnn/models/allegro.py +601 -0
  106. xnns-0.1.0/src/xnn/gnn/models/base.py +168 -0
  107. xnns-0.1.0/src/xnn/gnn/models/blocks.py +209 -0
  108. xnns-0.1.0/src/xnn/gnn/models/cace.py +685 -0
  109. xnns-0.1.0/src/xnn/gnn/models/mace.py +1215 -0
  110. xnns-0.1.0/src/xnn/gnn/models/nequip.py +794 -0
  111. xnns-0.1.0/src/xnn/hybrid/__init__.py +18 -0
  112. xnns-0.1.0/src/xnn/hybrid/models/__init__.py +4 -0
  113. xnns-0.1.0/src/xnn/hybrid/models/bamboo.py +597 -0
  114. xnns-0.1.0/src/xnn/hybrid/models/dispersion.py +108 -0
  115. xnns-0.1.0/src/xnn/transformer/__init__.py +18 -0
  116. xnns-0.1.0/src/xnn/transformer/attention.py +109 -0
  117. xnns-0.1.0/src/xnn/transformer/featurizers/__init__.py +4 -0
  118. xnns-0.1.0/src/xnn/transformer/featurizers/radial.py +110 -0
  119. xnns-0.1.0/src/xnns.egg-info/PKG-INFO +422 -0
  120. xnns-0.1.0/src/xnns.egg-info/SOURCES.txt +146 -0
  121. xnns-0.1.0/src/xnns.egg-info/dependency_links.txt +1 -0
  122. xnns-0.1.0/src/xnns.egg-info/entry_points.txt +2 -0
  123. xnns-0.1.0/src/xnns.egg-info/requires.txt +74 -0
  124. xnns-0.1.0/src/xnns.egg-info/top_level.txt +1 -0
  125. xnns-0.1.0/tests/test_allegro.py +183 -0
  126. xnns-0.1.0/tests/test_ani.py +404 -0
  127. xnns-0.1.0/tests/test_ase_io.py +146 -0
  128. xnns-0.1.0/tests/test_atom_typing.py +155 -0
  129. xnns-0.1.0/tests/test_bamboo.py +309 -0
  130. xnns-0.1.0/tests/test_benchmark.py +533 -0
  131. xnns-0.1.0/tests/test_cace.py +225 -0
  132. xnns-0.1.0/tests/test_deploy_torchscript.py +298 -0
  133. xnns-0.1.0/tests/test_frc.py +380 -0
  134. xnns-0.1.0/tests/test_gnn.py +116 -0
  135. xnns-0.1.0/tests/test_hub.py +840 -0
  136. xnns-0.1.0/tests/test_les.py +375 -0
  137. xnns-0.1.0/tests/test_mace.py +195 -0
  138. xnns-0.1.0/tests/test_neighborlist.py +113 -0
  139. xnns-0.1.0/tests/test_neighborlist_backends.py +118 -0
  140. xnns-0.1.0/tests/test_nequip.py +221 -0
  141. xnns-0.1.0/tests/test_opls.py +831 -0
  142. xnns-0.1.0/tests/test_physnet.py +241 -0
  143. xnns-0.1.0/tests/test_reaxff.py +604 -0
  144. xnns-0.1.0/tests/test_schnet.py +315 -0
  145. xnns-0.1.0/tests/test_smoke.py +94 -0
  146. xnns-0.1.0/tests/test_structure_to_graph_device.py +70 -0
  147. xnns-0.1.0/tests/test_torch_compat.py +56 -0
  148. xnns-0.1.0/tests/test_trainer_distributed.py +64 -0
xnns-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MolSSI AI
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.
xnns-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,422 @@
1
+ Metadata-Version: 2.4
2
+ Name: xnns
3
+ Version: 0.1.0
4
+ Summary: Machine-learning interatomic potentials in PyTorch for molecular and periodic systems
5
+ Author-email: Mohammad Mostafanejad <smostafanejad@molssi.org>
6
+ Maintainer-email: MolSSI AI <smostafanejad@molssi.org>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/molssi-ai/xnn
9
+ Project-URL: Documentation, https://molssi-ai.github.io/xnn/
10
+ Project-URL: Source, https://github.com/molssi-ai/xnn
11
+ Project-URL: Issues, https://github.com/molssi-ai/xnn/issues
12
+ Project-URL: Changelog, https://github.com/molssi-ai/xnn/releases
13
+ Keywords: interatomic potentials,machine learning,molecular dynamics,MACE,NequIP,Allegro,SchNet,PhysNet,ANI,ReaxFF,OPLS,pytorch,LAMMPS,ASE
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
23
+ Classifier: Topic :: Scientific/Engineering :: Physics
24
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: torch>=2.0
29
+ Requires-Dist: numpy
30
+ Requires-Dist: pyyaml
31
+ Requires-Dist: tqdm
32
+ Provides-Extra: ase
33
+ Requires-Dist: ase>=3.22; extra == "ase"
34
+ Provides-Extra: hub
35
+ Requires-Dist: h5py>=3.0; extra == "hub"
36
+ Provides-Extra: gnn
37
+ Requires-Dist: e3nn>=0.4.4; extra == "gnn"
38
+ Provides-Extra: mdi
39
+ Requires-Dist: pymdi>=1.4; extra == "mdi"
40
+ Provides-Extra: vesin
41
+ Requires-Dist: vesin-torch>=0.3; extra == "vesin"
42
+ Provides-Extra: hydra
43
+ Requires-Dist: hydra-core>=1.3; extra == "hydra"
44
+ Requires-Dist: omegaconf>=2.3; extra == "hydra"
45
+ Provides-Extra: dev
46
+ Requires-Dist: pytest; extra == "dev"
47
+ Provides-Extra: docs
48
+ Requires-Dist: sphinx>=7; extra == "docs"
49
+ Requires-Dist: pydata-sphinx-theme>=0.15; extra == "docs"
50
+ Requires-Dist: sphinx-design; extra == "docs"
51
+ Requires-Dist: sphinx-copybutton; extra == "docs"
52
+ Requires-Dist: sphinx-togglebutton; extra == "docs"
53
+ Requires-Dist: myst-nb>=1.1; extra == "docs"
54
+ Provides-Extra: examples
55
+ Requires-Dist: ase>=3.22; extra == "examples"
56
+ Requires-Dist: e3nn>=0.4.4; extra == "examples"
57
+ Requires-Dist: h5py>=3.0; extra == "examples"
58
+ Requires-Dist: mace-torch==0.3.16; extra == "examples"
59
+ Requires-Dist: nequip==0.6.2; extra == "examples"
60
+ Requires-Dist: matplotlib>=3.8; extra == "examples"
61
+ Requires-Dist: jupyter; extra == "examples"
62
+ Requires-Dist: ipykernel; extra == "examples"
63
+ Requires-Dist: nbconvert; extra == "examples"
64
+ Requires-Dist: nbformat; extra == "examples"
65
+ Requires-Dist: openmm>=8.0; extra == "examples"
66
+ Requires-Dist: rdkit>=2023.9; extra == "examples"
67
+ Provides-Extra: ani
68
+ Requires-Dist: torchani==2.2.4; extra == "ani"
69
+ Requires-Dist: h5py>=3.0; extra == "ani"
70
+ Provides-Extra: ffnn
71
+ Requires-Dist: rdkit>=2023.9; extra == "ffnn"
72
+ Provides-Extra: opls
73
+ Requires-Dist: openmm>=8.0; extra == "opls"
74
+ Requires-Dist: rdkit>=2023.9; extra == "opls"
75
+ Provides-Extra: all
76
+ Requires-Dist: ase>=3.22; extra == "all"
77
+ Requires-Dist: e3nn>=0.4.4; extra == "all"
78
+ Requires-Dist: vesin-torch>=0.3; extra == "all"
79
+ Requires-Dist: hydra-core>=1.3; extra == "all"
80
+ Requires-Dist: omegaconf>=2.3; extra == "all"
81
+ Requires-Dist: pytest; extra == "all"
82
+ Requires-Dist: mace-torch==0.3.16; extra == "all"
83
+ Requires-Dist: nequip==0.6.2; extra == "all"
84
+ Requires-Dist: matplotlib>=3.8; extra == "all"
85
+ Requires-Dist: jupyter; extra == "all"
86
+ Requires-Dist: ipykernel; extra == "all"
87
+ Requires-Dist: nbconvert; extra == "all"
88
+ Requires-Dist: nbformat; extra == "all"
89
+ Dynamic: license-file
90
+
91
+ # xnn
92
+
93
+ Machine-learning interatomic potentials for **molecules and materials** behind a
94
+ single coherent PyTorch interface.
95
+
96
+ ## Installation
97
+
98
+ From PyPI, where the distribution is called `xnns` (the import name and the
99
+ command line are `xnn`):
100
+
101
+ ```
102
+ pip install xnns # core (torch, numpy, pyyaml)
103
+ pip install "xnns[gnn,ase]" # + e3nn for NequIP/MACE/Allegro, + ASE calculator
104
+ ```
105
+
106
+ From a clone, for development:
107
+
108
+ ```
109
+ pip install -e . # core (torch, numpy, pyyaml)
110
+ pip install -e ".[ase]" # + ASE calculator
111
+ pip install -e ".[gnn]" # + e3nn for NequIP/MACE/Allegro
112
+ pip install -e ".[hydra]" # + Hydra/OmegaConf config
113
+ pip install -e ".[examples]" # + ASE, e3nn, mace-torch, nequip, jupyter (runs the notebooks)
114
+ pip install -e ".[all]"
115
+ ```
116
+
117
+ The Allegro reference implementation used by one fidelity notebook is not on
118
+ PyPI; install it separately with
119
+ `pip install "git+https://github.com/mir-group/allegro@v0.3.0"`.
120
+
121
+ ## Quick start
122
+
123
+ ```bash
124
+ # builds trains a model on toy data and predicts on a test set
125
+ python examples/quickstart.py
126
+
127
+ # smoke tests for all models and families
128
+ pytest tests/
129
+ ```
130
+
131
+ ```python
132
+ from xnn.common.config import Config
133
+ from xnn.common.data import AtomicDataset
134
+ from xnn.common.train import Trainer
135
+
136
+ cfg = Config()
137
+ # E.g. schnet | hdnnp | ani | physnet | nequip | mace | allegro | cace | reaxff
138
+ cfg.model.name = "nequip"
139
+ # Unshared model specific hyperparameters go here
140
+ cfg.model.extra = {"species": [1, 6, 8], "l_max": 2}
141
+ # batch_size = 1 disables batch training
142
+ cfg.data.batch_size = 16
143
+ # auto | cpu | cuda | cuda:0
144
+ cfg.device = "auto"
145
+ Trainer(cfg, AtomicDataset(structures, cfg.model.cutoff)).fit()
146
+ ```
147
+
148
+ `structures` is a list of plain dictionaries (`pos`, `atomic_numbers`, and
149
+ optionally, `cell`/`pbc` and `energy`/`forces`/`stress` targets). Data in any
150
+ ASE-native format loads directly and targets can also be included. So, no
151
+ pre-wrapping is required:
152
+
153
+ ```python
154
+ # xnn supports ase-io native formats such as .extxyz, .cif, VASP, ...
155
+ train_set = AtomicDataset.from_file("trajectory.extxyz", cutoff=4.0)
156
+ ```
157
+
158
+ ## Design principles
159
+
160
+ Four ideas hold `xnn` together:
161
+
162
+ 1. **Unified data object.** Every model consumes an `AtomicGraph` and returns
163
+ `{"node_energy", "energy"}`. Molecular vs. periodic is invisible to models:
164
+ periodicity lives only in `edge_vectors()` (`r_ij = pos[dst] - pos[src] +
165
+ cell_shift @ cell`), keeping forces and stress differentiable.
166
+ 2. **Featurizers are first-class.** A `Featurizer` (subclass of `nn.Module`)
167
+ turns a graph into invariant descriptors (symmetry functions, AEV) or
168
+ equivariant edge attributes (spherical harmonics, Cartesian monomials).
169
+ Descriptor models (HDNNP, ANI) and GNNs (NequIP/MACE/Allegro/CACE) are thin
170
+ compositions over featurizers, so the featurization is reusable and
171
+ inspectable on its own.
172
+ 3. **Forces/stress in one place.** `ForceStressOutput` wraps any model and
173
+ differentiates energy w.r.t. positions (forces) and a symmetric strain
174
+ (stress). Models never implement them. The same wrapper idea powers
175
+ `LatentEwald` (Latent Ewald Summation, Cheng 2025): every model exposes
176
+ invariant `"node_features"`, so long-range electrostatics/dispersion can be
177
+ added to *any* short-range model with `extra: {long_range: {...}}` — a
178
+ faithful port of the CACE-LR reference implementation (see
179
+ `tests/test_les.py` and `examples/gnn/les/`).
180
+ 4. **Extensibility via registry + one config, three frontends.**
181
+ `@register_model("name")` + a `from_config` classmethod makes a model usable
182
+ from any of YAML / argparse / Hydra, which all funnel into one
183
+ `Config` dataclass.
184
+
185
+
186
+ ```python
187
+ # Data (structures dict -> AtomicGraph)
188
+ from xnn.common.data import AtomicDataset, build_neighbor_list
189
+ ds = AtomicDataset(structures, cutoff=5.0)
190
+ graph = ds[0]
191
+
192
+ # Featurizers (AtomicGraph -> model inputs)
193
+ from xnn.dnn.featurizers import AEV, RadialSymmetryFunctions
194
+ from xnn.gnn.featurizers import SphericalHarmonicEdgeEmbedding
195
+ # (N, D) invariant per-atom AEV
196
+ descriptor = AEV(species=[1, 6, 8])(graph)
197
+ # Equivariant edge attributes
198
+ edges = SphericalHarmonicEdgeEmbedding(l_max=2)(graph)
199
+
200
+ # Models (model inputs -> energy)
201
+ from xnn.common.models import build_model, ForceStressOutput, available_models
202
+ # Any registered model + autograd forces/stress
203
+ model = ForceStressOutput(build_model(cfg.model))
204
+ ```
205
+
206
+ ## Config frontends (interchangeable)
207
+
208
+ ```python
209
+ from xnn.common.config import from_yaml, from_argparse, from_hydra
210
+ cfg = from_yaml("configs/train.yaml")
211
+ cfg = from_argparse(["--config", "configs/train.yaml", "--set", "model.cutoff=6.0"])
212
+ ```
213
+
214
+ CLI: `xnn train --config configs/train.yaml --set optim.epochs=50`
215
+ (also `xnn benchmark --config configs/benchmark.yaml` and
216
+ `xnn export --config ... --ckpt ... --to lammps|torchscript`).
217
+
218
+ Model keys copied verbatim from an upstream code's yaml also work: a per-model
219
+ key-translation registry (`xnn.common.config.translate`) rewrites the foreign
220
+ spellings (MACE-CLI `r_max`/`num_radial_basis`/`atomic_numbers`/`E0s`, NequIP
221
+ `num_layers`, ...) to the xnn canonical names at config-load time; the xnn
222
+ spelling wins if both are given. Extend it for another code with
223
+ `register_key_translation("name", {...})`.
224
+
225
+ ## Deployment
226
+
227
+ ```python
228
+ from xnn.common.deploy import XNNCalculator, export_to_lammps
229
+ atoms.calc = XNNCalculator(model, cutoff=5.0) # ASE
230
+ export_to_lammps(model, cutoff=5.0, path="deployed.pt") # TorchScript for LAMMPS
231
+ ```
232
+
233
+ Pair the exported `.pt` with the matching C++ pair style (pair_nequip /
234
+ pair_mace / pair_allegro pattern). The `LAMMPSWrapper` in
235
+ `common/deploy/lammps.py` defines the tensor ABI. A model is exportable when it
236
+ provides the scriptable `node_energy(atomic_numbers, edge_index, edge_vec)`
237
+ core -- SchNet, NequIP, MACE and Allegro all do (the scripted models reproduce
238
+ the eager ones to ~1e-15, verified in `tests/test_schnet.py` /
239
+ `tests/test_mace.py` / `tests/test_nequip.py` / `tests/test_allegro.py`). For NequIP this required a scriptable, bit-exact stand-in
240
+ for e3nn's `Gate` (`xnn.gnn.models.nequip._Gate`), which the e3nn 0.4.4
241
+ original cannot do on torch 2.x.
242
+
243
+ ## Benchmarking
244
+
245
+ Score a set of **pre-trained** models on one dataset with
246
+ `xnn.common.benchmark` and tabulate their errors. A single config lists the
247
+ `models` (each an architecture plus the `checkpoint` to load) and the
248
+ `metrics` mapping, which ties each target quantity (`energy` / `forces` /
249
+ `stress`) to the error metrics reported for it (`mae` / `mse` / `rmse`, or
250
+ custom callables). Results are tabulated per model and
251
+ written to CSV / JSON / Markdown (or a user-registered format). Energy can be
252
+ scored per atom or, with `atomic_energies` (a `{Z: E0}` map or `average` to fit
253
+ from data), as the physically meaningful atomization (interaction) energy.
254
+ Benchmarking does not train — produce the checkpoints first with `xnn train`.
255
+
256
+ ```bash
257
+ xnn benchmark --config configs/benchmark.yaml
258
+ ```
259
+
260
+ ```python
261
+ from xnn.common.benchmark import from_yaml, run_benchmark
262
+ rows = run_benchmark(from_yaml("configs/benchmark.yaml"))
263
+ ```
264
+
265
+ The benchmark builds models with the same `Config` and model registry as a
266
+ single run; new metrics and output formats plug in via `@register_metric` and
267
+ `@register_writer`, mirroring `@register_model`.
268
+
269
+ ## Available models
270
+
271
+ | Model | Family | Featurizers | State |
272
+ |---|---|---|---|
273
+ | SchNet | cnn | Gaussian RBF | Under development |
274
+ | PhysNet | dnn | exp-Gaussian rbf + attention masks | Complete: Training, Evaluation, Deployment (ASE only) |
275
+ | HDNNP | dnn | radial symmetry functions (G2) | Under development |
276
+ | ANI | dnn | AEV (radial + angular symmetry functions) | Complete: Training, Evaluation, Deployment (ASE only) |
277
+ | NequIP | gnn | spherical-harmonic edges | Complete: Training, Evaluation, Deployment (TorchScript, LAMMPS, ASE) |
278
+ | MACE | gnn | spherical-harmonic edges | Complete: Training, Evaluation, Deployment (TorchScript, LAMMPS, ASE) |
279
+ | CACE | gnn | Cartesian monomial edges | Complete: Training, Evaluation, Deployment (ASE only) |
280
+ | Allegro | gnn | spherical-harmonic edges | Complete: Training, Evaluation, Deployment (TorchScript, LAMMPS, ASE) |
281
+ | BAMBOO | hybrid | exp-normal rbf + multi-head edge attention | Complete: Training, Evaluation, Deployment (ASE only) |
282
+ | ReaxFF / ReaxFF-nn | ffnn | bond orders + EEM charges (the force field is the model) | Complete: Training, Evaluation, Deployment (ASE only) |
283
+ | OPLS / OPLS-AA / L-OPLS | ffnn | fixed valence topology (the force field is the model) | Complete: Training, Evaluation, Deployment (ASE only) |
284
+
285
+
286
+ <details> <!-- Start Package layout -->
287
+ <summary><h2 style="display:inline-block">Package layout</h2></summary>
288
+
289
+ The package is organized **by model family** (`gnn`, `cnn`, `dnn`, `ffnn`, `hybrid`),
290
+ with shared resources factored into the `common` modules and reusable
291
+ transformer building blocks in `transformer`. An object (e.g., function, module
292
+ etc.) lives with the model family that uses it, or with `common` if more than
293
+ one family needs it. Of course, layers are designed as stand-alone entities and
294
+ can be imported on their own.
295
+
296
+ ```
297
+ src/xnn/
298
+ ├── __main__.py `python -m xnn` entry point
299
+ ├── common/ shared across all model families
300
+ │ ├── data/ - common data abstractions
301
+ │ │ └── … + AtomicGraph (the one data object), PBC neighbor list, AtomicDataset, ASE I/O
302
+ │ ├── featurizers/ - common featurizers
303
+ │ │ └── … + Featurizer base + shared basis functions (GaussianRBF, CosineCutoff)
304
+ │ ├── config/ - one dataclass schema; loaders for yaml / argparse / hydra
305
+ │ │ └── … + schema, loaders, translate, coerce
306
+ │ ├── models/ - InteratomicPotential interface, registry, ForceStressOutput, ops (scatter_sum, shifted_softplus)
307
+ │ │ └── … + base, registry, outputs, les, ops
308
+ │ ├── train/ - Trainer (batch + device aware), weighted energy/force/stress loss
309
+ │ │ └── … + trainer, losses
310
+ │ ├── benchmark/ - score pre-trained models on a dataset (metrics, atomization energy, report writers)
311
+ │ │ └── … + config, runner, metrics, energy, report
312
+ │ ├── deploy/ - ASE Calculator, and LAMMPS/TorchScript export
313
+ │ │ └── … + ase_calculator, lammps
314
+ │ └── cli/ - the `xnn` command-line interface
315
+ │ └── main.py
316
+ ├── gnn/ graph potentials
317
+ │ ├── featurizers/ - GNN featurizers
318
+ │ │ └── … + spherical, cartesian, radial, cutoff
319
+ │ └── models/ - base (GNNPotential, EquivariantGNN), blocks, nequip, mace, allegro, cace
320
+ │ └── … + base, blocks, nequip, mace, allegro, cace
321
+ ├── cnn/ continuous-filter conv net
322
+ │ └── models/ - schnet
323
+ ├── dnn/ descriptor + per-element networks, and PhysNet
324
+ │ ├── featurizers/ - DNN featurizers
325
+ │ │ └── … + symmetry functions, AEV
326
+ │ └── models/ base (DescriptorPotential), hdnnp, ani, physnet and ported Grimme's D3
327
+ │ └── …
328
+ ├── ffnn/ learnable classical force fields
329
+ │ ├── common/ - frc (SEAMM .frc force-field files: reader, resolver, writer, registry),
330
+ │ │ typing (SMARTS atom typing), elements
331
+ │ ├── data/ - shipped parameter files: oplsaa.frc, lopls.frc, oplsaa_1996.frc, reaxff/*.frc
332
+ │ └── models/ - reaxff, ffield, opls, oplslib, topology
333
+ │ └── … + ReaxFF / ReaxFF-nn reactive force field, OPLS / L-OPLS fixed-topology
334
+ │ force field, the .frc <-> model parameter bridges
335
+ ├── transformer/ shared graph-transformer building blocks
336
+ │ ├── attention.py - EdgeMultiheadAttention (multi-head QKV attention on edges)
337
+ │ └── featurizers/ - ExpNormalSmearing radial basis
338
+ └── hybrid/ GNN + transformer potentials with a physics energy split
339
+ └── models/ - bamboo (BAMBOO graph equivariant transformer), dispersion (D3(CSO))
340
+ └── …
341
+ ```
342
+
343
+ </details> <!-- End Package layout -->
344
+
345
+ <details> <!-- Start Examples -->
346
+ <summary><h2 style="display:inline-block">Examples</h2></summary>
347
+
348
+ Runnable, pre-executed notebooks live under `examples/` (`pip install -e
349
+ ".[examples]"`). They are grouped by model family, where the leading letter of
350
+ `<xnn>` names the architecture type (`gnn` graph, `cnn` convolutional, `dnn`
351
+ deep/descriptor, `ffnn` force-field, `hybrid` mixed):
352
+
353
+ - **Per-model training and MD** (`examples/<xnn>/<model>/`):
354
+ + `<model>_argon_train_test.ipynb` and `<model>_argon_density_md.ipynb` for
355
+ MACE, NequIP, Allegro, CACE and PhysNet.
356
+ + `schnet_rmd17_train.ipynb` and `schnet_ethanol_md.ipynb` for SchNet.
357
+ + `ani_rmd17_train.ipynb` plus the `ani1*_dataset.ipynb` / `ani2x_dataset.ipynb`
358
+ dataset walk-throughs for ANI.
359
+ + `les_molecular_dimers.ipynb` for the LES long-range wrapper (charged and
360
+ polar dimers) and `recreate_mace_architecture.ipynb` for a block-by-block
361
+ MACE rebuild.
362
+ + `bamboo_dimer_electrostatics.ipynb` and `bamboo_charge_analysis.ipynb` for
363
+ the hybrid BAMBOO model.
364
+ - **Force fields** (`examples/ffnn/`):
365
+ + `reaxff/reaxff_rmd17_train_test.ipynb` trains the ReaxFF-nn reactive force
366
+ field on rMD17 and `reaxff/reaxff_md_bond_orders.ipynb` analyses its bond
367
+ orders, EEM charges and bond dissociation in MD. Both benchmark against the
368
+ published classical Chenoweth 2008 C/H/O field, loaded from the shipped
369
+ SEAMM `.frc` file (`ReaxFF("CHO_cho_2008")`).
370
+ + `opls/opls_conformational_energetics.ipynb` reproduces Table 1 of the 1996
371
+ OPLS-AA paper with a relaxed dihedral driver, typing every molecule from
372
+ coordinates with the SMARTS templates of `oplsaa.frc`.
373
+ + `opls/opls_lopls_torsion_refit.ipynb` re-derives the L-OPLS hydrocarbon
374
+ torsion refit of Siu et al. (2012) by gradient descent
375
+ (`trainable=("dihedral_v",)`) and writes the trained field back out as a
376
+ `.frc` file.
377
+ - **Data and deployment:**
378
+ + `data/load_dataset_tutorial.ipynb` covers the one-line dataset hub used by
379
+ every training notebook (`load_dataset("argon_md")`, `load_dataset("rmd17",
380
+ ...)`, `load_dataset("ani1", ...)`, `load_dataset("lode_dimers",
381
+ subset="bio_scan")`).
382
+ + `deploy/mdi_argon_md.ipynb` and `deploy/mdi_argon_lammps.ipynb` drive a
383
+ trained model from an external MD code through the MDI engine.
384
+ + `examples/quickstart.py` is a minimal train/predict script on toy data.
385
+ - **Fidelity checks** (`examples/fidelity_checks/<model>_verification.ipynb`):
386
+ + Block-by-block numerical comparisons against the upstream codes for MACE,
387
+ NequIP, Allegro, CACE, SchNet, PhysNet, ANI, BAMBOO and LES.
388
+ + OPLS is verified against OpenMM (an independent MD engine, optional
389
+ dependency) in `opls_verification.ipynb` and `tests/test_opls.py`.
390
+ + **ReaxFF is the exception:** the authors' reference implementation of
391
+ ReaxFF-nn is AGPL-licensed, so no verification notebook or test depending
392
+ on it (and no code derived from it) is distributed with this MIT-licensed
393
+ code base. The implementation follows the published equations, was checked
394
+ against that implementation during development without redistributing
395
+ anything from it, and ships with self-contained equation-by-equation tests
396
+ instead (`tests/test_reaxff.py`; see the fidelity notes in the
397
+ documentation).
398
+
399
+ </details> <!-- End Examples -->
400
+
401
+ <details> <!-- Start Extension points -->
402
+ <summary><h2 style="display:inline-block">Extension points</h2></summary>
403
+
404
+ - **Implement a new model:**
405
+ + Pick your model family package (`gnn` / `cnn` / `dnn`/ `ffnn`, or add one)
406
+ and add a module under `<family>/models/`.
407
+ + Subclass `xnn.common.models.InteratomicPotential` (or the family base,
408
+ e.g., `gnn.models.base.EquivariantGNN`) and implement its `forward(data)`
409
+ method.
410
+ + register your model implementation using `@register_model` decorator.
411
+ + Add a YAML config file for your model `configs/model/<name>.yaml`.
412
+ + Import the family package so the model registers.
413
+ + For TorchScript/LAMMPS export, it is important to expose a scriptable
414
+ `node_energy(atomic_numbers, edge_index, edge_vec)` core (SchNet shows the
415
+ pattern; e3nn models need e3nn's JIT support for this).
416
+ - **Add a new featurizer:**
417
+ + Subclass `xnn.common.featurizers.Featurizer` and implement `output_dim` and
418
+ `forward(data)`. Put the resulting featurizer module in the
419
+ `common/featurizers/` if shared by more than one model family or under the
420
+ using family's `featurizers/` if it is only used by that one model family.
421
+
422
+ </details> <!-- End Extension points -->