lammps-analysis-tools 1.0.0__py3-none-any.whl

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 (74) hide show
  1. lammps_analysis_tools-1.0.0.dist-info/LICENSE +14 -0
  2. lammps_analysis_tools-1.0.0.dist-info/METADATA +231 -0
  3. lammps_analysis_tools-1.0.0.dist-info/RECORD +74 -0
  4. lammps_analysis_tools-1.0.0.dist-info/WHEEL +5 -0
  5. lammps_analysis_tools-1.0.0.dist-info/entry_points.txt +2 -0
  6. lammps_analysis_tools-1.0.0.dist-info/top_level.txt +1 -0
  7. lat/__init__.py +3 -0
  8. lat/__main__.py +6 -0
  9. lat/cli.py +270 -0
  10. lat/config.py +106 -0
  11. lat/core/__init__.py +6 -0
  12. lat/core/context.py +155 -0
  13. lat/core/correlate.py +67 -0
  14. lat/core/errors.py +60 -0
  15. lat/core/frame.py +74 -0
  16. lat/core/grid.py +59 -0
  17. lat/core/io/__init__.py +184 -0
  18. lat/core/io/gmx.py +223 -0
  19. lat/core/io/lammps_data.py +210 -0
  20. lat/core/io/lammps_dump.py +81 -0
  21. lat/core/neighbor.py +104 -0
  22. lat/core/output.py +133 -0
  23. lat/core/pbc.py +140 -0
  24. lat/core/periodic.py +694 -0
  25. lat/core/selection.py +216 -0
  26. lat/core/table.py +90 -0
  27. lat/core/topology.py +145 -0
  28. lat/core/unwrap.py +68 -0
  29. lat/data/lat.yaml +259 -0
  30. lat/data/manual/README.md +44 -0
  31. lat/data/manual/agg.md +57 -0
  32. lat/data/manual/cluster.md +56 -0
  33. lat/data/manual/common.md +111 -0
  34. lat/data/manual/contact.md +54 -0
  35. lat/data/manual/density.md +55 -0
  36. lat/data/manual/describe.md +47 -0
  37. lat/data/manual/freevol.md +60 -0
  38. lat/data/manual/gyrate.md +49 -0
  39. lat/data/manual/hbond.md +61 -0
  40. lat/data/manual/msd.md +55 -0
  41. lat/data/manual/occupancy.md +54 -0
  42. lat/data/manual/pistack.md +55 -0
  43. lat/data/manual/plot1d.md +50 -0
  44. lat/data/manual/plot2d.md +45 -0
  45. lat/data/manual/rdf.md +55 -0
  46. lat/data/manual/residence.md +56 -0
  47. lat/data/manual/rms.md +54 -0
  48. lat/data/manual/sasa.md +53 -0
  49. lat/data/manual/select.md +52 -0
  50. lat/data/manual/transport.md +55 -0
  51. lat/docs.py +55 -0
  52. lat/modules/__init__.py +54 -0
  53. lat/modules/_graph.py +130 -0
  54. lat/modules/agg.py +162 -0
  55. lat/modules/base.py +58 -0
  56. lat/modules/cluster.py +89 -0
  57. lat/modules/contact.py +106 -0
  58. lat/modules/density.py +164 -0
  59. lat/modules/describe.py +42 -0
  60. lat/modules/freevol.py +328 -0
  61. lat/modules/gyrate.py +88 -0
  62. lat/modules/hbond.py +374 -0
  63. lat/modules/msd.py +144 -0
  64. lat/modules/occupancy.py +179 -0
  65. lat/modules/pistack.py +129 -0
  66. lat/modules/rdf.py +175 -0
  67. lat/modules/residence.py +188 -0
  68. lat/modules/rms.py +158 -0
  69. lat/modules/sasa.py +78 -0
  70. lat/modules/select.py +67 -0
  71. lat/modules/transport.py +187 -0
  72. lat/plotting/__init__.py +6 -0
  73. lat/plotting/plot1d.py +161 -0
  74. lat/plotting/plot2d.py +78 -0
@@ -0,0 +1,14 @@
1
+ Copyright (c) 2026 tgraphite. All rights reserved.
2
+
3
+ This software and its accompanying documentation (the "Software") are
4
+ proprietary. No permission is granted to use, copy, modify, merge, publish,
5
+ distribute, sublicense, or sell copies of the Software without the prior
6
+ written permission of the copyright holder.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
13
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
14
+ SOFTWARE.
@@ -0,0 +1,231 @@
1
+ Metadata-Version: 2.1
2
+ Name: lammps-analysis-tools
3
+ Version: 1.0.0
4
+ Summary: Trajectory analysis for LAMMPS data/dump files, with GROMACS-compatible commands
5
+ Author: tgraphite
6
+ License: Proprietary
7
+ Project-URL: Homepage, https://github.com/tgraphite/LammpsAnalysisTools
8
+ Project-URL: Documentation, https://github.com/tgraphite/LammpsAnalysisTools/tree/main/docs/manual
9
+ Project-URL: Repository, https://github.com/tgraphite/LammpsAnalysisTools
10
+ Project-URL: Issues, https://github.com/tgraphite/LammpsAnalysisTools/issues
11
+ Keywords: molecular dynamics,LAMMPS,GROMACS,trajectory analysis,RDF,hydrogen bonds,free volume,SASA
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: Other/Proprietary License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
23
+ Classifier: Topic :: Scientific/Engineering :: Physics
24
+ Requires-Python: >=3.9
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: numpy >=1.22
28
+ Requires-Dist: scipy >=1.8
29
+ Requires-Dist: pyyaml >=5.4
30
+ Requires-Dist: matplotlib >=3.5
31
+ Requires-Dist: MDAnalysis >=2.4
32
+ Requires-Dist: ase >=3.22
33
+
34
+ # lat — LAMMPS Analysis Tool
35
+
36
+ [![PyPI](https://img.shields.io/pypi/v/lammps-analysis-tools.svg)](https://pypi.org/project/lammps-analysis-tools/)
37
+ [![Python](https://img.shields.io/pypi/pyversions/lammps-analysis-tools.svg)](https://pypi.org/project/lammps-analysis-tools/)
38
+
39
+ 面向 LAMMPS `data` / `lammpstrj` 的轨迹分析工具。命令风格对齐 GROMACS(`-s` 拓扑、`-f` 轨迹、单横线参数),
40
+ 输出统一为带审计头的 CSV,适合脚本批处理、回归与作图。
41
+
42
+ ## 特性
43
+
44
+ - **直接读 LAMMPS**:`*.data` / `*.lmp` + `*.lammpstrj`,自动识别 `atom_style`,按质量推断元素。
45
+ - **GROMACS 兼容输入**:`.tpr/.gro/.pdb` + `.xtc/.trr/.gro` 可直接分析,便于交叉验证。
46
+ - **周期几何一致性**:所有距离、质心、整分子复原、网格与曲面都走同一套最小镜像实现。
47
+ - **可复现输出**:文件名即意图;CSV 头记录命令、选择、参数、警告与标量;同名输出自动备份。
48
+ - **自解释**:`lat --help` 列出模块,`lat <module> -h` 给出参数与默认值,`lat describe -module <name>` 给出完整契约。
49
+
50
+ ## 安装
51
+
52
+ 需要 Python ≥ 3.9。
53
+
54
+ pip install lammps-analysis-tools
55
+
56
+ 安装后命令是 `lat`:
57
+
58
+ lat --version
59
+ lat --help
60
+
61
+ 升级:
62
+
63
+ pip install --upgrade lammps-analysis-tools
64
+
65
+ 从源码或离线安装:
66
+
67
+ git clone https://github.com/tgraphite/LammpsAnalysisTools.git
68
+ cd LammpsAnalysisTools
69
+ bash install.sh
70
+ export PATH="$HOME/.local/bin:$PATH"
71
+
72
+ `install.sh` 会建独立虚拟环境、安装依赖,并把 `lat` 放到 `~/.local/bin`;系统 Python < 3.9 时会用
73
+ `uv` 引导一个私有 Python 3.11。也可以直接 `pip install .`。
74
+
75
+ 依赖:numpy、scipy、pyyaml、matplotlib、MDAnalysis、ase。
76
+
77
+ ## 快速开始
78
+
79
+ # 径向分布函数 + 配位数
80
+ lat rdf -s system.data -f run.lammpstrj -sel1 "type 2" -sel2 "type 5" -cutoff 10 -o out
81
+
82
+ # 沿 z 的密度剖面
83
+ lat density -s system.data -f run.lammpstrj -axis z -nbins 200 -o out
84
+
85
+ # 均方位移与扩散系数
86
+ lat msd -s system.data -f run.lammpstrj -sel "type 2" -o out
87
+
88
+ # 画图(输入是上一步的 CSV)
89
+ lat plot1d -f out.rdf.out.csv -o rdf.png
90
+
91
+ 结果写入当前目录或 `-o` 指定的基名:
92
+
93
+ out.rdf.out.csv
94
+ out.rdf.cn.out.csv
95
+
96
+ ## 支持输入
97
+
98
+ | | 拓扑 | 轨迹 |
99
+ |---|---|---|
100
+ | LAMMPS(首选) | `.data` / `.lmp`:Masses、Atoms;含 Bonds 才能做氢键/整分子分析 | `.lammpstrj`(dump) |
101
+ | GROMACS | `.tpr` / `.gro` / `.pdb` | `.xtc` / `.trr` / `.gro` |
102
+
103
+ - 自动识别 `atomic`、`charge`、`molecular`、`full`,支持 `full/kk` 等加速器后缀;六列歧义时用 `-style`。
104
+ - 类型→元素默认按质量 ±0.2% 匹配;不确定时用 `-types` 显式指定,或让 dump 带 `element` 列。
105
+ - 坐标支持 `x/y/z`、`xu/yu/zu`、`xs/ys/zs`、`xsu/ysu/zsu`;带 `ix/iy/iz` 可解包。
106
+ - 反应轨迹原子数逐帧变化时会报错,并提示用 `-frame_range` / `-stride` 限定到一致窗口。
107
+
108
+ ## 模块总览
109
+
110
+ | 模块 | 用途 | 手册 |
111
+ |---|---|---|
112
+ | `rdf` | 径向分布函数 g(r) 与配位数 | [rdf](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/rdf.md) |
113
+ | `density` | 一维/二维密度剖面 | [density](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/density.md) |
114
+ | `msd` | 均方位移与扩散系数 | [msd](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/msd.md) |
115
+ | `gyrate` | 回转半径 Rg | [gyrate](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/gyrate.md) |
116
+ | `rms` | RMSD / RMSF | [rms](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/rms.md) |
117
+ | `contact` | 两组间接触数与距离 | [contact](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/contact.md) |
118
+ | `hbond` | 氢键数量、寿命与空间分布 | [hbond](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/hbond.md) |
119
+ | `agg` | SSIP / CIP / AGG 离子聚合形态 | [agg](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/agg.md) |
120
+ | `cluster` | 配位数与团簇尺寸分布 | [cluster](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/cluster.md) |
121
+ | `pistack` | π–π 堆积 | [pistack](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/pistack.md) |
122
+ | `freevol` | 自由体积、孔径分布、连通性 | [freevol](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/freevol.md) |
123
+ | `sasa` | 溶剂可及表面积 | [sasa](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/sasa.md) |
124
+ | `residence` | 配体滞留时间 | [residence](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/residence.md) |
125
+ | `transport` | 扩散、Nernst–Einstein、Green–Kubo | [transport](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/transport.md) |
126
+ | `occupancy` | 区域占据、穿越、首次通过 | [occupancy](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/occupancy.md) |
127
+ | `select` | 检查选择、导出 .ndx | [select](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/select.md) |
128
+ | `describe` | 模块清单与契约 | [describe](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/describe.md) |
129
+ | `plot1d` | 一维 CSV 绘图 | [plot1d](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/plot1d.md) |
130
+ | `plot2d` | 二维 CSV 绘图 | [plot2d](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/plot2d.md) |
131
+
132
+ 完整手册(公共参数、输入、选择语法、输出契约):[docs/manual](https://github.com/tgraphite/LammpsAnalysisTools/tree/main/docs/manual)。
133
+
134
+ ## 公共参数
135
+
136
+ | 参数 | 说明 |
137
+ |---|---|
138
+ | `-s, -topo` | 拓扑文件(分析模块必填) |
139
+ | `-f, -traj` | 轨迹文件 |
140
+ | `-o` | 输出基名;缺省用拓扑文件名 |
141
+ | `-unit` | 长度单位:`real`、`metal`、`lj`;缺省用配置 |
142
+ | `-style` | 强制 LAMMPS `atom_style` |
143
+ | `-types` | type→元素映射文件,每行 `type element` |
144
+ | `-index, -n` | GROMACS `.ndx`,为选择提供命名组 |
145
+ | `-frame_range` | 帧窗口 `start:stop[:stride]`,stop 不含 |
146
+ | `-stride` | 每隔多少帧取一帧 |
147
+ | `-v` | 显示 INFO 进度 |
148
+ | `-debug` | 额外写 JSON 审计 |
149
+ | `-h` | 模块帮助(含默认值) |
150
+ | `-V, --version` | 版本号 |
151
+
152
+ PBC 始终开启,所有距离使用最小镜像。时间轴是帧号,不解析文件中的物理时间。
153
+
154
+ ## 选择语法
155
+
156
+ MDAnalysis 风格子集,支持 `and`、`or`、`not` 与括号;相邻关键字隐含 `and`。
157
+
158
+ | 关键字 | 含义 | LAMMPS | GROMACS |
159
+ |---|---|---|---|
160
+ | `all` | 全部原子 | 是 | 是 |
161
+ | `type` | 原子类型 | 是 | 是 |
162
+ | `element` | 元素符号 | 是(需推断或 `-types`) | 是 |
163
+ | `mol` | 分子 ID | 是(需分子信息) | 是 |
164
+ | `id` | 原子 id | 是 | 是 |
165
+ | `index` | 0-based 原子序号 | 是 | 是 |
166
+ | `name` | 原子名 | 否 | 是 |
167
+ | `resname` | 残基名 | 否 | 是 |
168
+ | `resid` | 残基号 | 否 | 是 |
169
+
170
+ -sel "type 2"
171
+ -sel "type 2 or type 5"
172
+ -sel1 "resname LI" -sel2 "resname FSI"
173
+ -sel "all and not type 1"
174
+
175
+ 单选择模块用 `-sel`;双选择模块用 `-sel1`/`-sel2`。先运行 `lat select` 验证命中。
176
+
177
+ ## 输出
178
+
179
+ - 结果全部写入 CSV;stdout 为空,进度/警告/错误走 stderr。
180
+ - 文件名:`<basename>.<tag>[.<mode>].out.csv`。
181
+ - 文件头以 `#` 开头,包含 program、module、command、selections、definitions、frame_range、
182
+ scalars、warning、title、xlabel、ylabel、columns,最后是 `# --- data ---`。
183
+ - 标量(首壳配位数、D、R²、寿命、积分等)在 `# scalars:` 行,分号分隔。
184
+ - 同名文件先备份为 `.bak.1`、`.bak.2`……,不会静默覆盖。
185
+ - 退出码:0 成功,1 参数/输入/计算错误,130 中断;警告不改变退出码。
186
+
187
+ ## 绘图
188
+
189
+ `plot1d` / `plot2d` 只读 CSV,计算与绘图解耦。
190
+
191
+ lat plot1d -f out.rdf.out.csv -o rdf.png
192
+ lat plot1d -f out.agg.labels.out.csv -columns A_SSIP,A_CIP,A_AGG -o spec.png
193
+ lat plot1d -f out.agg.labels.out.csv -stack -o spec_stack.png
194
+ lat plot2d -f out.density.2d.out.csv -o density2d.png
195
+
196
+ `-smooth`(`none`/`gaussian`/`savgol`)只在绘图阶段生效,CSV 始终是原始值;
197
+ `-bar` 与 `-stack` 互斥,且不做平滑。
198
+
199
+ ## 配置
200
+
201
+ 默认值来自 `lat.yaml`:源码树是 `config/lat.yaml`,安装后是包内 `data/lat.yaml`。
202
+ 命令行覆盖配置。
203
+
204
+ | 环境变量 | 作用 |
205
+ |---|---|
206
+ | `LAT_CONFIG` | 使用自定义配置文件 |
207
+ | `LAT_VENV` | `install.sh` 创建的虚拟环境路径 |
208
+ | `LAT_BIN` | `install.sh` 放置 `lat` 的目录 |
209
+ | `PYTHON` | `install.sh` 使用的解释器 |
210
+
211
+ ## 文档
212
+
213
+ - 逐模块手册:[docs/manual](https://github.com/tgraphite/LammpsAnalysisTools/tree/main/docs/manual)
214
+ - 公共参数与输出契约:[common.md](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/manual/common.md)
215
+ - 版本变更:[CHANGELOG.md](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/docs/CHANGELOG.md)
216
+
217
+ ## 常见问题
218
+
219
+ **选择命中 0 个原子?** 用 `lat select` 检查表达式;LAMMPS 拓扑通常没有 `resname`/`name`。
220
+
221
+ **元素推断失败?** 补 `Masses`,或让 dump 带 `element` 列,或用 `-types`。
222
+
223
+ **氢键报 “no donor”?** 给体只认 N/O/F/S/Cl/Br/I 上的 H;C–H 不是给体。
224
+
225
+ **MSD 提示没有 image flags?** 轨迹只有 wrapped 坐标,MSD 可能饱和;改用带 `xu/yu/zu` 或 `ix/iy/iz` 的 dump。
226
+
227
+ **freevol 报三斜盒?** 体素网格只支持正交且固定的盒子;改用分子/原子对分析或正交化盒子。
228
+
229
+ ## 许可
230
+
231
+ Proprietary。详见 [LICENSE](https://github.com/tgraphite/LammpsAnalysisTools/blob/main/LICENSE)。
@@ -0,0 +1,74 @@
1
+ lat/__init__.py,sha256=_08jkCobSbDO7MmSOi76TV4OTzIxDt9haScRSuCIVUI,59
2
+ lat/__main__.py,sha256=4JMK66Wj4uLZTKbF-sT3LAxOsr6buig77PmOkJCRRxw,83
3
+ lat/cli.py,sha256=IY-PdlxT2QDyTNaq63aQSPyI-ePaJbB0RpcLT8v4E8M,10637
4
+ lat/config.py,sha256=dLCb5geWzA-4Gu4l_LQar4m9os-BvbEeg1CeGKQFPH0,3250
5
+ lat/docs.py,sha256=9BUyIm5f8IxF2E0QZzCqt5Uid1RHfQ3tLWctnvBgCxM,1545
6
+ lat/core/__init__.py,sha256=rpCVNW7D8SoA1kSsO-dN7u-TLEXOW92DftQGZiUkwV8,277
7
+ lat/core/context.py,sha256=gQ9aTQfECZ-00D1MJ6U9SwQjYc1ctvQKd3I7hOpn9KI,6219
8
+ lat/core/correlate.py,sha256=7K-tC2DCN2S1g1Yff7cc-TyoFE7kB1cH_xlv4o4dh7I,2187
9
+ lat/core/errors.py,sha256=O0MFv-yUO_fFt3AfLThiyroEYwMZ1KEaw4CIlFpEuUI,1604
10
+ lat/core/frame.py,sha256=9kDl8BVmnyb05Hi9zMeympHDsNNRttX3nxoLJak3qsI,2759
11
+ lat/core/grid.py,sha256=Uexh80WPKEFo6sFfLj8CiGLzWSadLmHQqk9FKa_b7P0,2055
12
+ lat/core/neighbor.py,sha256=A9V1xavPyfibtftRFW_rKDHRZBmiM7JL34mSK_QUN88,3664
13
+ lat/core/output.py,sha256=7mtf6afvUTPg6peTox2rHuuhTwFQR29mrK0pVTJr7dE,3939
14
+ lat/core/pbc.py,sha256=hPGiqjUDfYNelXabY6s0XQizVXqASe2qCy19-Lic7uU,5173
15
+ lat/core/periodic.py,sha256=XSAxjjqCasHJrSA7NqK1aoxR_ig8-fvpL5eKxceue_Q,26916
16
+ lat/core/selection.py,sha256=2M9BkAUzfXk5YHMcALlvKM4PugvAobl0LTVw6HjE50k,7401
17
+ lat/core/table.py,sha256=8tGh6g1TyyT57bu7FDGYsoJZhHUGd8AI0TUvjSxH3nQ,2634
18
+ lat/core/topology.py,sha256=kpzQx4x-qfUijthUMdPtIB7ZnBKnM7nsPpdzXamc5e4,5184
19
+ lat/core/unwrap.py,sha256=7eU4ZDP9K2O8cZzbk_xYksjEXZYQMidk_oMeoybUv2U,2428
20
+ lat/core/io/__init__.py,sha256=Czboss4kdeGoZHyEL5t7l3b90yxl73fVWmL6rySvvx0,6504
21
+ lat/core/io/gmx.py,sha256=CEkVtwZVzkClW2SvBnl5XXIzdiVi9V6LuUWtZgP0NiM,8528
22
+ lat/core/io/lammps_data.py,sha256=bjYP6DtCWu0pMPcAQxWGN66BkeSEP7g5pyYsmQo49Nw,7749
23
+ lat/core/io/lammps_dump.py,sha256=7FuiQbVvgyN1yWUCGbd1QGOZ5mbkH7NeJcXsSwCCArk,3048
24
+ lat/data/lat.yaml,sha256=DPmjL_xmbefB7DPjAtiApubzPc5E-nGnfWT4pvXCJ2g,6429
25
+ lat/data/manual/README.md,sha256=TvAJzXpMgLoWMqC-u36aYvNLeJTNqz42cbvCUoNWW_M,2193
26
+ lat/data/manual/agg.md,sha256=JHLz66tBC89wEXkuED0wC6g8Q2mMyOVixG4iySWnGlM,2735
27
+ lat/data/manual/cluster.md,sha256=PC8ZKV4-4WZcMU9YXmaTM8xByLL540R3VSwwtDtCRSM,2242
28
+ lat/data/manual/common.md,sha256=lVG65e7N-FTYjeGgGnCeMJcNnjJVTrcc2Nk6awU5epg,5289
29
+ lat/data/manual/contact.md,sha256=mj8m8J9nNUSyAA6oKVVrAU-b8sDmX0tmGhM_8yj3XRY,2366
30
+ lat/data/manual/density.md,sha256=Irx7rPdb1Yk_WAeFI3l99V1Eb33y6HQWGAPN03oeU-Q,2429
31
+ lat/data/manual/describe.md,sha256=Ykii0F1mGeD3QlJ0aRzwGIXs3NhI6ZQ71kfV78tkET4,1396
32
+ lat/data/manual/freevol.md,sha256=71Xw0oBMgDZkaZGmLD9gou-grVA_kOBcyfQ0noVAsHA,3103
33
+ lat/data/manual/gyrate.md,sha256=brj5wynFu74uyE3tCNUw552lvuVsK8kpVjFpfbcXCLE,1849
34
+ lat/data/manual/hbond.md,sha256=Ki1pesR46Hmp-FrtQ5ijBwv-ve33ZYAyeE_uiGt2L80,2984
35
+ lat/data/manual/msd.md,sha256=BqFUh0Mw4runZmCayGqzP9X5j6e_7zIV5oTya5-Pi7k,2389
36
+ lat/data/manual/occupancy.md,sha256=SFJ1-EcMmiLZtaSvO6Hpp7rbCyUeRXpjLqiy9ghVesY,2320
37
+ lat/data/manual/pistack.md,sha256=GHU6VyBC1iIB4dnT47yWcaZHalRRDH0Ef9WkynpWo9c,2186
38
+ lat/data/manual/plot1d.md,sha256=BwCLO6xANdzPTBPhAXXV734ZnVxKxlbf775_diOf8yI,2157
39
+ lat/data/manual/plot2d.md,sha256=jCCTpN8RQXny_T0jx1ok2aG2mPldMhYeMl2zLF5gDGI,1386
40
+ lat/data/manual/rdf.md,sha256=usplbv6kCt9nKJBOo4zMXKIxrx7Mf5EFu3pI3b6WmiM,2678
41
+ lat/data/manual/residence.md,sha256=ycA2MrrMXQ0QsGJRkw8NWVl3cnvl3pPGw8eS5KLujvE,2430
42
+ lat/data/manual/rms.md,sha256=Cw7xAuIEl6gCFkHANhmIVqQycmrs9nZS_jF2pBqnP0A,1885
43
+ lat/data/manual/sasa.md,sha256=wifONC48wGVWXWPlydW_zPhsaOJ2QY4A6_QotEHUG50,2103
44
+ lat/data/manual/select.md,sha256=NqqdGzuIIbUlp--D6b592-e8lLzM0acDIk1uBsPksLw,1919
45
+ lat/data/manual/transport.md,sha256=ZpluEjZCSKPZ8teUaU0SvqNMrYOF7ItB2xph6suFAxc,2363
46
+ lat/modules/__init__.py,sha256=4sLaqGQe0PlpLi_tCy3V9AA7x38OjtI_ltvdrG5RG04,1018
47
+ lat/modules/_graph.py,sha256=MZZnkUS1XYOpBSbR0nwZUyMix5EczQdJBvLZhfz7CM4,4671
48
+ lat/modules/agg.py,sha256=zqTB4Em4tuSzfy4px3iQQfhvTVtJV82Xr_Eel4rWMHI,7116
49
+ lat/modules/base.py,sha256=wMg8UrbQrxqepgnvBz9bc67ywo4zaz-0weNK3n6Q40E,1684
50
+ lat/modules/cluster.py,sha256=08Ls2RZYPzLMJXTvYI4V1-gXmO8zDEQ-SCvTYTPHhcY,4068
51
+ lat/modules/contact.py,sha256=ypxOgOnf1d5LjMhc30iwtWFMJjIqSy1ehxuaHxx_ta0,5223
52
+ lat/modules/density.py,sha256=B2sJ5oK-_zd-uo2VDHoFiHOTWius4On1tnGLJoWNlgo,6796
53
+ lat/modules/describe.py,sha256=KHIRqZjv18KB7sXdWFHrJA7sD8xFMyBrf0EIzn_YB3g,1384
54
+ lat/modules/freevol.py,sha256=9faFrq_WaQew4BG7AzKJhmi8-KFD1iX_LywrhBGxqPM,15415
55
+ lat/modules/gyrate.py,sha256=ySh_mQFvSNeNFs1M8w-Sb_AHBOo0jN0gimEZCNcpX74,3582
56
+ lat/modules/hbond.py,sha256=OhV68WM_kRYHLsbHmYe3iuFfE3J017fJVh8g_X_K2h0,14911
57
+ lat/modules/msd.py,sha256=MyBtnZenjo5-MN3vDdEYsEmfRHYqYM65yu6QgaWDTt8,5586
58
+ lat/modules/occupancy.py,sha256=5-xJXMH7thhr7K6DixcKlbx3Q_RmtFOC-bCpLEd62kw,7347
59
+ lat/modules/pistack.py,sha256=d8LCLuGSgIXL-biURkhOjmIEBg9W-1AkV_ZvoVlCnoY,5618
60
+ lat/modules/rdf.py,sha256=eJV981C55lYHQqHmD6BfzpIWbyZHP0748ku_zk2Eqr0,6867
61
+ lat/modules/residence.py,sha256=kiqoUcmoz2Hs1-HoIoc8giLUpFL7vTMaoZrX3dPJktA,7577
62
+ lat/modules/rms.py,sha256=jp093XWbmSK0lO0y8uT2CNpr8RQ9wIRfCFVVnneay-M,6139
63
+ lat/modules/sasa.py,sha256=QkuvkNvd7bBL-tZM1Cst6vF4GDV5eI9gIojzR3KueVY,3359
64
+ lat/modules/select.py,sha256=thtgMK28gEwB75os4YDYeaokybxg41njlNA1etpvX1E,2738
65
+ lat/modules/transport.py,sha256=mh45dp9svltlZHXf-0uos0FoI3-EgaJohijJzWz8Mh8,7806
66
+ lat/plotting/__init__.py,sha256=0ZnzpHadshqLFHpnIjGLiPUrHIyghXBEaxDdKEZ3xN0,189
67
+ lat/plotting/plot1d.py,sha256=DhkM2ZF-0IvTdNEwhFrzLiaGhsyq7lJ_n-DkVUH-DzI,5781
68
+ lat/plotting/plot2d.py,sha256=Hjr9CRZbtHa4YHqjBbh1HQhnJxSqASflBFZcdi4Gy9E,2760
69
+ lammps_analysis_tools-1.0.0.dist-info/LICENSE,sha256=VoRURheY1Xmtlomv4tvkvlSZbBjH0BXJ_ncieFHd1Ug,777
70
+ lammps_analysis_tools-1.0.0.dist-info/METADATA,sha256=tHltDQ7MlzGbZfr3VmxCHZDb_YmLvSTInQ9YXd4uRrI,11354
71
+ lammps_analysis_tools-1.0.0.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
72
+ lammps_analysis_tools-1.0.0.dist-info/entry_points.txt,sha256=VtlsI-b3Z3N06E5rchT1YUBrVCD6tsK5L-5NGEgzOjg,37
73
+ lammps_analysis_tools-1.0.0.dist-info/top_level.txt,sha256=G6os795izf-wFzozl8F4xCW-epxSDb0hIH32xx1AGQY,4
74
+ lammps_analysis_tools-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.41.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ lat = lat.cli:main
lat/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """lat — LAMMPS Analysis Tool."""
2
+
3
+ __version__ = "1.0.0"
lat/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ import sys
2
+
3
+ from .cli import main
4
+
5
+ if __name__ == "__main__":
6
+ sys.exit(main())
lat/cli.py ADDED
@@ -0,0 +1,270 @@
1
+ """lat command line: lat <module> -s <data> -f <traj> [...]."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import sys
8
+ from pathlib import Path
9
+
10
+ from . import __version__
11
+ from .config import load as load_config
12
+ from .core.context import Context
13
+ from .core.errors import LatError, Logger, get_logger, set_logger
14
+ from .core.io import open_system
15
+ from .core.output import write_all
16
+ from .core.selection import read_ndx
17
+ from .modules import all_modules, get
18
+
19
+ _ALLOWED_UNITS = {"real", "metal", "lj"}
20
+
21
+
22
+ def _type_of(type_name):
23
+ return {"str": str, "int": int, "float": float}.get(type_name)
24
+
25
+
26
+ def build_parser(cls, cfg=None) -> argparse.ArgumentParser:
27
+ epilog = (f"manual: docs/{cls.help_doc or 'manual/index.md'} | "
28
+ f"`lat describe -module {cls.name}` for the full contract; "
29
+ "defaults come from the lat config")
30
+ parser = argparse.ArgumentParser(
31
+ prog=f"lat {cls.name}", description=cls.summary, epilog=epilog,
32
+ formatter_class=argparse.RawDescriptionHelpFormatter, add_help=True
33
+ )
34
+ if getattr(cls, "requires_topology", True):
35
+ parser.add_argument("-s", "-topo", dest="topo", required=True,
36
+ help="topology: LAMMPS .data/.lmp (or GROMACS .tpr/.gro/.pdb)")
37
+ parser.add_argument("-f", "-traj", dest="traj",
38
+ help="trajectory: LAMMPS .lammpstrj (or GROMACS .xtc/.trr/.gro)")
39
+ parser.add_argument("-o", dest="output",
40
+ help="output basename (default: topology file stem)")
41
+ parser.add_argument("-unit", dest="unit",
42
+ help="length unit: real|metal|lj (default: config io.default_unit)")
43
+ parser.add_argument("-style", dest="style",
44
+ help="force the LAMMPS atom_style when the Atoms header is ambiguous")
45
+ parser.add_argument("-types", dest="types",
46
+ help="explicit type->element file (one 'type element' pair per line)")
47
+ parser.add_argument("-index", "-n", dest="index",
48
+ help="GROMACS .ndx file providing named groups for selections")
49
+ parser.add_argument("-debug", dest="debug", action="store_true",
50
+ help="also write a JSON audit next to the CSV")
51
+ parser.add_argument("-v", dest="verbose", action="store_true",
52
+ help="show INFO progress on stderr")
53
+ for p in cls.params:
54
+ help_text = p.help
55
+ if p.config and cfg is not None:
56
+ val = cfg.get(p.config)
57
+ if val is not None:
58
+ help_text = f"{help_text} [default: {val}]".strip()
59
+ kwargs = {"help": help_text}
60
+ if p.choices:
61
+ kwargs["choices"] = list(p.choices)
62
+ if p.type == "flag":
63
+ parser.add_argument(*p.flags, dest=p.name, action="store_true", default=None, **kwargs)
64
+ else:
65
+ parser.add_argument(*p.flags, dest=p.name, type=_type_of(p.type), default=None, **kwargs)
66
+ return parser
67
+
68
+
69
+ def _parse_types_file(path) -> dict[int, str]:
70
+ mapping = {}
71
+ with open(path) as fh:
72
+ for line in fh:
73
+ line = line.split("#")[0].strip()
74
+ if not line:
75
+ continue
76
+ parts = line.replace(",", " ").split()
77
+ if len(parts) < 2:
78
+ continue
79
+ a, b = parts[0], parts[1]
80
+ if a.isdigit():
81
+ mapping[int(a)] = b.capitalize()
82
+ elif b.isdigit():
83
+ mapping[int(b)] = a.capitalize()
84
+ if not mapping:
85
+ raise LatError(f"{path}: no type->element pairs parsed")
86
+ return mapping
87
+
88
+
89
+ def _run_plot(kind: str, argv) -> int:
90
+ parser = argparse.ArgumentParser(prog=f"lat {kind}")
91
+ parser.add_argument("-f", dest="csv", required=True,
92
+ help="lat output CSV (header carries title/xlabel/ylabel/columns)")
93
+ parser.add_argument("-o", dest="out", help="output image path")
94
+ parser.add_argument("-title", dest="title", help="override the header title")
95
+ parser.add_argument("-smooth", dest="smooth", choices=("none", "gaussian", "savgol"),
96
+ help="smooth the plotted curve(s); the CSV stays raw")
97
+ if kind == "plot1d":
98
+ parser.add_argument("-columns", dest="columns", nargs="+", metavar="NAME",
99
+ help="only draw these y columns (comma- or space-separated); "
100
+ "the x axis is always the first column")
101
+ parser.add_argument("-bar", dest="bar", action="store_true",
102
+ help="grouped bar chart, one bar per y column")
103
+ parser.add_argument("-stack", dest="stack", action="store_true",
104
+ help="stacked bar chart; y columns are normalized to "
105
+ "occupancy fractions")
106
+ args = parser.parse_args(argv)
107
+ from .plotting import plot1d, plot2d
108
+
109
+ cfg = load_config()
110
+ smooth = args.smooth or str(cfg.get("plot.smooth", default="none") or "none")
111
+ sm = {
112
+ "window": int(cfg.get("plot.savgol_window", default=5) or 5),
113
+ "order": int(cfg.get("plot.savgol_order", default=2) or 2),
114
+ "sigma": float(cfg.get("plot.gaussian_sigma", default=1.0) or 1.0),
115
+ }
116
+ if kind == "plot1d":
117
+ if args.bar and args.stack:
118
+ raise LatError("-bar and -stack are mutually exclusive")
119
+ col_sel = None
120
+ if args.columns:
121
+ col_sel = [c for tok in args.columns
122
+ for c in (t.strip() for t in tok.split(",")) if c]
123
+ mode = "bar" if args.bar else "stack" if args.stack else "line"
124
+ out = plot1d(args.csv, out=args.out, title=args.title, smooth=smooth,
125
+ columns=col_sel, mode=mode, **sm)
126
+ else:
127
+ out = plot2d(args.csv, out=args.out, title=args.title, smooth=smooth, **sm)
128
+ print(f"wrote {out}", file=sys.stderr)
129
+ return 0
130
+
131
+
132
+ def _apply_config_paths(cfg) -> None:
133
+ pass
134
+
135
+
136
+ def main(argv=None) -> int:
137
+ argv = list(sys.argv[1:] if argv is None else argv)
138
+ if not argv or argv[0] in ("-h", "--help", "help"):
139
+ _top_help()
140
+ return 0
141
+ if argv[0] in ("-V", "--version"):
142
+ print(f"lat {__version__}")
143
+ return 0
144
+
145
+ module_name = argv[0]
146
+ if module_name in ("plot1d", "plot2d"):
147
+ try:
148
+ return _run_plot(module_name, argv[1:])
149
+ except LatError as exc:
150
+ print(f"[lat ERROR] {exc}", file=sys.stderr)
151
+ return 1
152
+
153
+ try:
154
+ cfg = load_config()
155
+ logger = Logger(level="warning")
156
+ set_logger(logger)
157
+ cls = get(module_name)
158
+ parser = build_parser(cls, cfg)
159
+ args = parser.parse_args(argv[1:])
160
+
161
+ if getattr(args, "verbose", None):
162
+ logger.level = "info"
163
+ elif cfg.get("logger.level"):
164
+ logger.level = str(cfg.get("logger.level"))
165
+
166
+ command = "lat " + " ".join(argv)
167
+ _execute(cls, args, cfg, command)
168
+ return 0
169
+ except LatError as exc:
170
+ print(f"[lat ERROR] {exc}", file=sys.stderr)
171
+ return 1
172
+ except KeyboardInterrupt:
173
+ print("[lat ERROR] interrupted", file=sys.stderr)
174
+ return 130
175
+
176
+
177
+ def _execute(cls, args, cfg, command):
178
+ logger = get_logger()
179
+ provided = {}
180
+ for p in cls.params:
181
+ provided[p.name] = getattr(args, p.name, None)
182
+ params = cls.resolve_defaults(cfg, provided)
183
+
184
+ mod = cls()
185
+ if not getattr(cls, "requires_topology", True):
186
+ mod.run(None, **params)
187
+ return []
188
+
189
+ unit = args.unit or cfg.get("io.default_unit")
190
+ if args.unit is None:
191
+ logger.info(f"no -unit given; assuming {unit} (Angstrom)")
192
+ if unit not in _ALLOWED_UNITS:
193
+ raise LatError(f"unit {unit!r} not supported (allowed: {sorted(_ALLOWED_UNITS)})")
194
+
195
+ ndx = read_ndx(args.index) if args.index else None
196
+ import time as _time
197
+ _t0 = _time.time()
198
+ logger.notice(f"reading topology {args.topo}")
199
+ topo, source = open_system(args.topo, args.traj, style=args.style, cfg=cfg)
200
+ logger.notice(f" parsed {topo.n_atoms} atoms in {_time.time() - _t0:.1f}s"
201
+ + (f"; trajectory {args.traj}" if args.traj else ""))
202
+
203
+ if args.types:
204
+ topo.type_element.update(_parse_types_file(args.types))
205
+ topo.element_problems = {}
206
+
207
+ ctx = Context(topo, source, cfg=cfg, unit=unit, command=command,
208
+ debug=bool(args.debug), ndx=ndx)
209
+
210
+ tables = mod.run(ctx, **params)
211
+ emitted = set()
212
+ for t in tables:
213
+ for w in t.warnings:
214
+ if w not in emitted:
215
+ logger.warning(w)
216
+ emitted.add(w)
217
+ if getattr(cls, "screen_only", False) or not tables:
218
+ return tables
219
+
220
+ basename = args.output or Path(args.topo).stem
221
+ outdir = Path(basename).parent if Path(basename).parent != Path("") else Path(".")
222
+ stem = Path(basename).name
223
+ out_cfg = cfg.get("output", default={}) or {}
224
+ paths = write_all(
225
+ tables,
226
+ basename=stem,
227
+ outdir=outdir,
228
+ ext=out_cfg.get("ext", "csv"),
229
+ suffix=out_cfg.get("suffix", "out"),
230
+ prefix=out_cfg.get("header_prefix", "#"),
231
+ float_format=out_cfg.get("float_format", "%.6g"),
232
+ atomic=bool(out_cfg.get("atomic_write", True)),
233
+ backup_on_conflict=bool(cfg.get("io.backup_on_conflict", default=True)),
234
+ include_audit=bool(out_cfg.get("include_audit", True)),
235
+ command=command,
236
+ version=__version__,
237
+ )
238
+ for path in paths:
239
+ logger.notice(f"wrote {path}")
240
+ if args.debug and out_cfg.get("debug_json", False):
241
+ audit = {
242
+ "command": command,
243
+ "version": __version__,
244
+ "config": str(cfg.path),
245
+ "tables": [{"tag": t.tag, "rows": t.n_rows, "scalars": t.scalars,
246
+ "selection": t.selection, "warnings": t.warnings} for t in tables],
247
+ "warnings": logger.warnings,
248
+ }
249
+ apath = Path(outdir) / f"{stem}.debug.json"
250
+ with open(apath, "w") as fh:
251
+ json.dump(audit, fh, indent=2)
252
+ logger.info(f"wrote {apath}")
253
+ return tables
254
+
255
+
256
+ def _top_help() -> None:
257
+ print("lat — LAMMPS Analysis Tool")
258
+ print(f"version {__version__}")
259
+ print("\nusage: lat <module> -s <data> [-f <traj>] [options]\n")
260
+ print("modules:")
261
+ for name in sorted(all_modules()):
262
+ print(f" {name:<12} {get(name).summary}")
263
+ print("\nplotting:")
264
+ print(" plot1d plot a 1D CSV")
265
+ print(" plot2d plot a 2D CSV")
266
+ print("\n describe -module <name> show a module's parameters and contract")
267
+
268
+
269
+ if __name__ == "__main__":
270
+ sys.exit(main())