sqq 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.
- sqq-0.1.0/PKG-INFO +212 -0
- sqq-0.1.0/README.md +190 -0
- sqq-0.1.0/pyproject.toml +42 -0
- sqq-0.1.0/setup.cfg +4 -0
- sqq-0.1.0/sqq/__init__.py +5 -0
- sqq-0.1.0/sqq/__main__.py +8 -0
- sqq-0.1.0/sqq/cli.py +62 -0
- sqq-0.1.0/sqq/config.py +150 -0
- sqq-0.1.0/sqq/core/__init__.py +1 -0
- sqq-0.1.0/sqq/core/cage.py +664 -0
- sqq-0.1.0/sqq/core/cup.py +168 -0
- sqq-0.1.0/sqq/core/f3f4.py +137 -0
- sqq-0.1.0/sqq/core/graph.py +173 -0
- sqq-0.1.0/sqq/core/ice.py +80 -0
- sqq-0.1.0/sqq/core/pbc.py +31 -0
- sqq-0.1.0/sqq/core/ring.py +81 -0
- sqq-0.1.0/sqq/core/selection.py +54 -0
- sqq-0.1.0/sqq/example/gro/test1.gro +11395 -0
- sqq-0.1.0/sqq/example/gro/test2.gro +45447 -0
- sqq-0.1.0/sqq/io/__init__.py +1 -0
- sqq-0.1.0/sqq/io/gro_writer.py +204 -0
- sqq-0.1.0/sqq/io/summary.py +1002 -0
- sqq-0.1.0/sqq/io/trajectory.py +152 -0
- sqq-0.1.0/sqq/models.py +141 -0
- sqq-0.1.0/sqq/pipeline.py +309 -0
- sqq-0.1.0/sqq.egg-info/PKG-INFO +212 -0
- sqq-0.1.0/sqq.egg-info/SOURCES.txt +31 -0
- sqq-0.1.0/sqq.egg-info/dependency_links.txt +1 -0
- sqq-0.1.0/sqq.egg-info/entry_points.txt +2 -0
- sqq-0.1.0/sqq.egg-info/requires.txt +10 -0
- sqq-0.1.0/sqq.egg-info/top_level.txt +1 -0
- sqq-0.1.0/tests/test_graph_ice.py +56 -0
- sqq-0.1.0/tests/test_ring_cup.py +78 -0
sqq-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sqq
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Shell Quant Qualifier for water-shell topology analysis in MD trajectories.
|
|
5
|
+
Author-email: pimooni <pimooni@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/pimooni/sqq
|
|
7
|
+
Project-URL: Repository, https://github.com/pimooni/sqq
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: numpy
|
|
14
|
+
Requires-Dist: pandas
|
|
15
|
+
Requires-Dist: openpyxl
|
|
16
|
+
Requires-Dist: pyyaml
|
|
17
|
+
Requires-Dist: tqdm
|
|
18
|
+
Requires-Dist: MDAnalysis
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest; extra == "dev"
|
|
21
|
+
Requires-Dist: networkx; extra == "dev"
|
|
22
|
+
|
|
23
|
+
# SQQ
|
|
24
|
+
|
|
25
|
+
**SQQ (Shell Quant Qualifier)** is a Python program for identifying and quantifying water-shell topologies in molecular dynamics trajectories.
|
|
26
|
+
|
|
27
|
+
It analyzes water, ice, and hydrate-like structures from MD frames by building a water network, finding rings, cups (half-cages), closed cages, guest occupancy, F3/F4 order metrics, and ice-like waters.
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
Development install from this directory:
|
|
32
|
+
|
|
33
|
+
```powershell
|
|
34
|
+
pip install -e .
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
After installation, use the unified command:
|
|
38
|
+
|
|
39
|
+
```powershell
|
|
40
|
+
sqq init -o config.yaml
|
|
41
|
+
sqq analyze -i ./gro -c config.yaml -o ./result_sqq
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
During local development without installation:
|
|
45
|
+
|
|
46
|
+
```powershell
|
|
47
|
+
python -m sqq init -o config.yaml
|
|
48
|
+
python -m sqq analyze -i ./gro -c config.yaml -o ./result_sqq
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
Single GRO file:
|
|
54
|
+
|
|
55
|
+
```powershell
|
|
56
|
+
sqq analyze -i test1.gro -c config.yaml -o ./result_sqq
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Directory of GRO frames:
|
|
60
|
+
|
|
61
|
+
```powershell
|
|
62
|
+
sqq analyze -i ./gro --pattern "*.gro" -c config.yaml -o ./result_sqq
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Parallel standalone GRO/XYZ frames:
|
|
66
|
+
|
|
67
|
+
```powershell
|
|
68
|
+
sqq analyze -i ./gro --n-jobs 4 -c config.yaml -o ./result_sqq
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
XTC/TRR trajectory with a topology/structure file:
|
|
72
|
+
|
|
73
|
+
```powershell
|
|
74
|
+
sqq analyze -i traj.xtc --top topol.gro -c config.yaml -o ./result_sqq
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Important Defaults
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
input:
|
|
81
|
+
xtc_stride: 1
|
|
82
|
+
|
|
83
|
+
graph:
|
|
84
|
+
bond_mode: auto
|
|
85
|
+
oo_cutoff_nm: 0.35
|
|
86
|
+
hbond_distance_nm: 0.35
|
|
87
|
+
hbond_angle_deg: 30.0
|
|
88
|
+
pair_file: null
|
|
89
|
+
pair_id: resid
|
|
90
|
+
|
|
91
|
+
ring:
|
|
92
|
+
sizes: [5, 6]
|
|
93
|
+
primitive: true
|
|
94
|
+
chordless: true
|
|
95
|
+
|
|
96
|
+
cup:
|
|
97
|
+
mode: general
|
|
98
|
+
enabled: true
|
|
99
|
+
base_sizes: auto
|
|
100
|
+
side_sizes: auto
|
|
101
|
+
|
|
102
|
+
cage:
|
|
103
|
+
enabled: true
|
|
104
|
+
ring_sizes: [5, 6]
|
|
105
|
+
target_types: [512, 51262, 51263, 51264]
|
|
106
|
+
output_other: false
|
|
107
|
+
other_max_faces: 20
|
|
108
|
+
search_mode: grow
|
|
109
|
+
seed_mode: ring
|
|
110
|
+
occupancy_mode: polyhedron
|
|
111
|
+
|
|
112
|
+
order:
|
|
113
|
+
focus_waters: []
|
|
114
|
+
|
|
115
|
+
parallel:
|
|
116
|
+
n_jobs: auto
|
|
117
|
+
|
|
118
|
+
output:
|
|
119
|
+
write_gro: true
|
|
120
|
+
write_tsv: false
|
|
121
|
+
write_vmd: false
|
|
122
|
+
write_xlsx_summary: true
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Configuration priority:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
built-in defaults < config.yaml < command-line options
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Output
|
|
132
|
+
|
|
133
|
+
SQQ writes HA-style per-frame folders plus global summaries:
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
result_sqq/
|
|
137
|
+
summary.xlsx
|
|
138
|
+
run_config.yaml
|
|
139
|
+
test1/
|
|
140
|
+
test1_info.md
|
|
141
|
+
test1_ring5.gro
|
|
142
|
+
test1_ring6.gro
|
|
143
|
+
test1_cup5_55555.gro
|
|
144
|
+
test1_512.gro
|
|
145
|
+
test1_512_empty.gro
|
|
146
|
+
test1_512_occupied.gro
|
|
147
|
+
test1_ice.gro
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Ring and cup outputs are free objects after cage ownership is removed. Cage GRO files include cage waters, CNT center atoms, and assigned guest molecules. Summary tables include per-cage-type empty/occupied/multi/guest columns and readable cage-isomer breakdowns.
|
|
151
|
+
Optional `*_membership.tsv` and `*_f3f4.tsv` files can be enabled with `output.write_tsv: true`.
|
|
152
|
+
|
|
153
|
+
## Implemented Analysis
|
|
154
|
+
|
|
155
|
+
- GRO and XYZ input in the source tree; XTC/TRR input through MDAnalysis when installed.
|
|
156
|
+
- Orthorhombic minimum-image PBC.
|
|
157
|
+
- Water and guest selection by residue and atom names.
|
|
158
|
+
- Shared water graph for ring, cup, cage, F3/F4, and ice metrics.
|
|
159
|
+
- `bond_mode=auto/hbond/oo/pairs`; `pairs` reads a user-provided water-neighbor file.
|
|
160
|
+
- Non-recursive DFS ring search for primitive/chordless rings.
|
|
161
|
+
- Ring search supports 4/5/6/7-member rings, but defaults to `[5, 6]`.
|
|
162
|
+
- General cup search from base rings and side-ring closure; by default cup base/side ring sizes follow `ring.sizes`, so `[4, 5, 6]` searches 4/5/6 cups and `[4, 5, 6, 7]` searches 4/5/6/7 cups.
|
|
163
|
+
- Default cage search by ring-face grow mode from ring seeds: grow connected face patches along open boundary edges, then validate a closed polyhedron by edge degree and Euler characteristic. Cage search supports 4/5/6-member faces through `cage.ring_sizes`, but defaults to `[5, 6]`; 7-member faces are intentionally not used for cage detection.
|
|
164
|
+
- Optional `cage.output_other: true` adds Euler-compatible 4/5/6 unconventional cage targets up to `cage.other_max_faces`; the default only searches `512`, `51262`, `51263`, and `51264`.
|
|
165
|
+
- Optional `cage.search_mode=pair` for HA/GRADE-style cup-pair comparison only.
|
|
166
|
+
- Default guest occupancy by `cage.occupancy_mode=polyhedron`, using an oriented solid-angle point-in-polyhedron test; `center` and `auto` modes are available for comparison/fallback.
|
|
167
|
+
- Cage isomer labels describe adjacent 6-ring face patterns, such as `6adj`, `6chain3`, `6star3`, or `6tri3+single`, instead of opaque `iso01` names.
|
|
168
|
+
- VMD helper colors: `512` blue, `51262` green, `51263` orange, `51264` red; ring centers use R4 gray, R5 purple, R6 tan, and R7 black.
|
|
169
|
+
- F3/F4 order metrics using the shared water graph and the reference-script formulas, including optional `order.focus_waters` averages.
|
|
170
|
+
- CHILL-style ice output: total ice-like waters, ice-I-like waters, and interfacial/intermediate ice waters.
|
|
171
|
+
- Explicit frame-level parallel execution for independent `.gro`/`.xyz` files via `--n-jobs N`.
|
|
172
|
+
|
|
173
|
+
## Main Parameters
|
|
174
|
+
|
|
175
|
+
| Parameter | Purpose |
|
|
176
|
+
| --- | --- |
|
|
177
|
+
| `water.resnames` | Water molecule residue names |
|
|
178
|
+
| `water.oxygen_names` | Oxygen atom names used as water graph nodes |
|
|
179
|
+
| `water.hydrogen_names` | Hydrogen atom names used for hydrogen-bond geometry |
|
|
180
|
+
| `guest.resnames` | Guest molecule residue names |
|
|
181
|
+
| `graph.bond_mode` | `auto`, `hbond`, `oo`, or `pairs` |
|
|
182
|
+
| `graph.pair_file` | Pair file used when `bond_mode=pairs`; each non-comment line has two ids |
|
|
183
|
+
| `graph.pair_id` | How pair ids are interpreted: `resid`, `oxygen_index`, or `atomid` |
|
|
184
|
+
| `ring.sizes` | Ring sizes to search; default `[5, 6]` |
|
|
185
|
+
| `cup.base_sizes`, `cup.side_sizes` | `auto` by default, meaning use `ring.sizes`; set explicit lists to restrict cup search |
|
|
186
|
+
| `cage.ring_sizes` | Ring-face sizes allowed in cage search; default `[5, 6]`, optional `[4, 5, 6]` |
|
|
187
|
+
| `cage.output_other` | Enable unconventional 4/5/6 cage targets; default `false` |
|
|
188
|
+
| `cage.other_max_faces` | Maximum face count for generated unconventional cage targets; default `20` |
|
|
189
|
+
| `cage.search_mode` | `grow` by default; `pair` for comparison/debugging |
|
|
190
|
+
| `cage.seed_mode` | `ring` by default for speed; `cup` starts grow from detected cups, `auto` uses cup seeds when cups exist and falls back to ring |
|
|
191
|
+
| `cage.occupancy_mode` | `polyhedron` by default; `center` and `auto` are also available |
|
|
192
|
+
| `input.xtc_stride` | Read every Nth XTC/TRR frame |
|
|
193
|
+
| `order.focus_waters` | Residue ids whose mean F3/F4 should also be reported |
|
|
194
|
+
| `parallel.n_jobs` / `--n-jobs` | Parallel worker count for independent `.gro`/`.xyz` files; default `auto` runs serially |
|
|
195
|
+
| `output.write_gro` | Write structure files for visualization |
|
|
196
|
+
|
|
197
|
+
## Current Limits
|
|
198
|
+
|
|
199
|
+
- CHILL-style ice classification is implemented as a topology/coordination classifier; separate atomistic Ih/Ic stacking assignment can be refined later if needed.
|
|
200
|
+
- Only orthorhombic boxes are supported in the implemented PBC path.
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
sqq-0.1.0/README.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# SQQ
|
|
2
|
+
|
|
3
|
+
**SQQ (Shell Quant Qualifier)** is a Python program for identifying and quantifying water-shell topologies in molecular dynamics trajectories.
|
|
4
|
+
|
|
5
|
+
It analyzes water, ice, and hydrate-like structures from MD frames by building a water network, finding rings, cups (half-cages), closed cages, guest occupancy, F3/F4 order metrics, and ice-like waters.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Development install from this directory:
|
|
10
|
+
|
|
11
|
+
```powershell
|
|
12
|
+
pip install -e .
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
After installation, use the unified command:
|
|
16
|
+
|
|
17
|
+
```powershell
|
|
18
|
+
sqq init -o config.yaml
|
|
19
|
+
sqq analyze -i ./gro -c config.yaml -o ./result_sqq
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
During local development without installation:
|
|
23
|
+
|
|
24
|
+
```powershell
|
|
25
|
+
python -m sqq init -o config.yaml
|
|
26
|
+
python -m sqq analyze -i ./gro -c config.yaml -o ./result_sqq
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
Single GRO file:
|
|
32
|
+
|
|
33
|
+
```powershell
|
|
34
|
+
sqq analyze -i test1.gro -c config.yaml -o ./result_sqq
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Directory of GRO frames:
|
|
38
|
+
|
|
39
|
+
```powershell
|
|
40
|
+
sqq analyze -i ./gro --pattern "*.gro" -c config.yaml -o ./result_sqq
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Parallel standalone GRO/XYZ frames:
|
|
44
|
+
|
|
45
|
+
```powershell
|
|
46
|
+
sqq analyze -i ./gro --n-jobs 4 -c config.yaml -o ./result_sqq
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
XTC/TRR trajectory with a topology/structure file:
|
|
50
|
+
|
|
51
|
+
```powershell
|
|
52
|
+
sqq analyze -i traj.xtc --top topol.gro -c config.yaml -o ./result_sqq
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Important Defaults
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
input:
|
|
59
|
+
xtc_stride: 1
|
|
60
|
+
|
|
61
|
+
graph:
|
|
62
|
+
bond_mode: auto
|
|
63
|
+
oo_cutoff_nm: 0.35
|
|
64
|
+
hbond_distance_nm: 0.35
|
|
65
|
+
hbond_angle_deg: 30.0
|
|
66
|
+
pair_file: null
|
|
67
|
+
pair_id: resid
|
|
68
|
+
|
|
69
|
+
ring:
|
|
70
|
+
sizes: [5, 6]
|
|
71
|
+
primitive: true
|
|
72
|
+
chordless: true
|
|
73
|
+
|
|
74
|
+
cup:
|
|
75
|
+
mode: general
|
|
76
|
+
enabled: true
|
|
77
|
+
base_sizes: auto
|
|
78
|
+
side_sizes: auto
|
|
79
|
+
|
|
80
|
+
cage:
|
|
81
|
+
enabled: true
|
|
82
|
+
ring_sizes: [5, 6]
|
|
83
|
+
target_types: [512, 51262, 51263, 51264]
|
|
84
|
+
output_other: false
|
|
85
|
+
other_max_faces: 20
|
|
86
|
+
search_mode: grow
|
|
87
|
+
seed_mode: ring
|
|
88
|
+
occupancy_mode: polyhedron
|
|
89
|
+
|
|
90
|
+
order:
|
|
91
|
+
focus_waters: []
|
|
92
|
+
|
|
93
|
+
parallel:
|
|
94
|
+
n_jobs: auto
|
|
95
|
+
|
|
96
|
+
output:
|
|
97
|
+
write_gro: true
|
|
98
|
+
write_tsv: false
|
|
99
|
+
write_vmd: false
|
|
100
|
+
write_xlsx_summary: true
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Configuration priority:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
built-in defaults < config.yaml < command-line options
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Output
|
|
110
|
+
|
|
111
|
+
SQQ writes HA-style per-frame folders plus global summaries:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
result_sqq/
|
|
115
|
+
summary.xlsx
|
|
116
|
+
run_config.yaml
|
|
117
|
+
test1/
|
|
118
|
+
test1_info.md
|
|
119
|
+
test1_ring5.gro
|
|
120
|
+
test1_ring6.gro
|
|
121
|
+
test1_cup5_55555.gro
|
|
122
|
+
test1_512.gro
|
|
123
|
+
test1_512_empty.gro
|
|
124
|
+
test1_512_occupied.gro
|
|
125
|
+
test1_ice.gro
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Ring and cup outputs are free objects after cage ownership is removed. Cage GRO files include cage waters, CNT center atoms, and assigned guest molecules. Summary tables include per-cage-type empty/occupied/multi/guest columns and readable cage-isomer breakdowns.
|
|
129
|
+
Optional `*_membership.tsv` and `*_f3f4.tsv` files can be enabled with `output.write_tsv: true`.
|
|
130
|
+
|
|
131
|
+
## Implemented Analysis
|
|
132
|
+
|
|
133
|
+
- GRO and XYZ input in the source tree; XTC/TRR input through MDAnalysis when installed.
|
|
134
|
+
- Orthorhombic minimum-image PBC.
|
|
135
|
+
- Water and guest selection by residue and atom names.
|
|
136
|
+
- Shared water graph for ring, cup, cage, F3/F4, and ice metrics.
|
|
137
|
+
- `bond_mode=auto/hbond/oo/pairs`; `pairs` reads a user-provided water-neighbor file.
|
|
138
|
+
- Non-recursive DFS ring search for primitive/chordless rings.
|
|
139
|
+
- Ring search supports 4/5/6/7-member rings, but defaults to `[5, 6]`.
|
|
140
|
+
- General cup search from base rings and side-ring closure; by default cup base/side ring sizes follow `ring.sizes`, so `[4, 5, 6]` searches 4/5/6 cups and `[4, 5, 6, 7]` searches 4/5/6/7 cups.
|
|
141
|
+
- Default cage search by ring-face grow mode from ring seeds: grow connected face patches along open boundary edges, then validate a closed polyhedron by edge degree and Euler characteristic. Cage search supports 4/5/6-member faces through `cage.ring_sizes`, but defaults to `[5, 6]`; 7-member faces are intentionally not used for cage detection.
|
|
142
|
+
- Optional `cage.output_other: true` adds Euler-compatible 4/5/6 unconventional cage targets up to `cage.other_max_faces`; the default only searches `512`, `51262`, `51263`, and `51264`.
|
|
143
|
+
- Optional `cage.search_mode=pair` for HA/GRADE-style cup-pair comparison only.
|
|
144
|
+
- Default guest occupancy by `cage.occupancy_mode=polyhedron`, using an oriented solid-angle point-in-polyhedron test; `center` and `auto` modes are available for comparison/fallback.
|
|
145
|
+
- Cage isomer labels describe adjacent 6-ring face patterns, such as `6adj`, `6chain3`, `6star3`, or `6tri3+single`, instead of opaque `iso01` names.
|
|
146
|
+
- VMD helper colors: `512` blue, `51262` green, `51263` orange, `51264` red; ring centers use R4 gray, R5 purple, R6 tan, and R7 black.
|
|
147
|
+
- F3/F4 order metrics using the shared water graph and the reference-script formulas, including optional `order.focus_waters` averages.
|
|
148
|
+
- CHILL-style ice output: total ice-like waters, ice-I-like waters, and interfacial/intermediate ice waters.
|
|
149
|
+
- Explicit frame-level parallel execution for independent `.gro`/`.xyz` files via `--n-jobs N`.
|
|
150
|
+
|
|
151
|
+
## Main Parameters
|
|
152
|
+
|
|
153
|
+
| Parameter | Purpose |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| `water.resnames` | Water molecule residue names |
|
|
156
|
+
| `water.oxygen_names` | Oxygen atom names used as water graph nodes |
|
|
157
|
+
| `water.hydrogen_names` | Hydrogen atom names used for hydrogen-bond geometry |
|
|
158
|
+
| `guest.resnames` | Guest molecule residue names |
|
|
159
|
+
| `graph.bond_mode` | `auto`, `hbond`, `oo`, or `pairs` |
|
|
160
|
+
| `graph.pair_file` | Pair file used when `bond_mode=pairs`; each non-comment line has two ids |
|
|
161
|
+
| `graph.pair_id` | How pair ids are interpreted: `resid`, `oxygen_index`, or `atomid` |
|
|
162
|
+
| `ring.sizes` | Ring sizes to search; default `[5, 6]` |
|
|
163
|
+
| `cup.base_sizes`, `cup.side_sizes` | `auto` by default, meaning use `ring.sizes`; set explicit lists to restrict cup search |
|
|
164
|
+
| `cage.ring_sizes` | Ring-face sizes allowed in cage search; default `[5, 6]`, optional `[4, 5, 6]` |
|
|
165
|
+
| `cage.output_other` | Enable unconventional 4/5/6 cage targets; default `false` |
|
|
166
|
+
| `cage.other_max_faces` | Maximum face count for generated unconventional cage targets; default `20` |
|
|
167
|
+
| `cage.search_mode` | `grow` by default; `pair` for comparison/debugging |
|
|
168
|
+
| `cage.seed_mode` | `ring` by default for speed; `cup` starts grow from detected cups, `auto` uses cup seeds when cups exist and falls back to ring |
|
|
169
|
+
| `cage.occupancy_mode` | `polyhedron` by default; `center` and `auto` are also available |
|
|
170
|
+
| `input.xtc_stride` | Read every Nth XTC/TRR frame |
|
|
171
|
+
| `order.focus_waters` | Residue ids whose mean F3/F4 should also be reported |
|
|
172
|
+
| `parallel.n_jobs` / `--n-jobs` | Parallel worker count for independent `.gro`/`.xyz` files; default `auto` runs serially |
|
|
173
|
+
| `output.write_gro` | Write structure files for visualization |
|
|
174
|
+
|
|
175
|
+
## Current Limits
|
|
176
|
+
|
|
177
|
+
- CHILL-style ice classification is implemented as a topology/coordination classifier; separate atomistic Ih/Ic stacking assignment can be refined later if needed.
|
|
178
|
+
- Only orthorhombic boxes are supported in the implemented PBC path.
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
sqq-0.1.0/pyproject.toml
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools >= 77.0.3", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sqq"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Shell Quant Qualifier for water-shell topology analysis in MD trajectories."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "pimooni", email = "pimooni@gmail.com" },
|
|
13
|
+
]
|
|
14
|
+
dependencies = [
|
|
15
|
+
"numpy",
|
|
16
|
+
"pandas",
|
|
17
|
+
"openpyxl",
|
|
18
|
+
"pyyaml",
|
|
19
|
+
"tqdm",
|
|
20
|
+
"MDAnalysis",
|
|
21
|
+
]
|
|
22
|
+
classifiers = [
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
25
|
+
"Operating System :: OS Independent",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = ["pytest", "networkx"]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
sqq = "sqq.cli:main"
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/pimooni/sqq"
|
|
36
|
+
Repository = "https://github.com/pimooni/sqq"
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.package-data]
|
|
39
|
+
sqq = ["example/gro/*.gro"]
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
testpaths = ["tests"]
|
sqq-0.1.0/setup.cfg
ADDED
sqq-0.1.0/sqq/cli.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""Command-line interface for SQQ."""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from .config import write_default_config
|
|
9
|
+
from .pipeline import analyze
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
HELP_BANNER = """
|
|
13
|
+
+----------------------------+
|
|
14
|
+
| Shell Quant Qualifier |
|
|
15
|
+
+----------------------------+
|
|
16
|
+
|
|
17
|
+
SQQ for MD water-shell topology analysis.
|
|
18
|
+
""".strip()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
22
|
+
"""Create the two-command CLI: init and analyze."""
|
|
23
|
+
parser = argparse.ArgumentParser(
|
|
24
|
+
prog="sqq",
|
|
25
|
+
description=HELP_BANNER,
|
|
26
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
27
|
+
)
|
|
28
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
29
|
+
|
|
30
|
+
init_parser = subparsers.add_parser("init", help="Write a default config.yaml file.")
|
|
31
|
+
init_parser.add_argument("-o", "--output", default="config.yaml", help="Output config path.")
|
|
32
|
+
|
|
33
|
+
analyze_parser = subparsers.add_parser("analyze", help="Analyze MD frames.")
|
|
34
|
+
analyze_parser.add_argument("-i", "--input", required=True, help="Input file or directory.")
|
|
35
|
+
analyze_parser.add_argument("--pattern", help="Input pattern when --input is a directory.")
|
|
36
|
+
analyze_parser.add_argument("--top", "--topology", dest="topology", help="Topology file for xtc/trr.")
|
|
37
|
+
analyze_parser.add_argument("-c", "--config", help="YAML config file.")
|
|
38
|
+
analyze_parser.add_argument("-o", "--output", default="result_sqq", help="Output directory.")
|
|
39
|
+
analyze_parser.add_argument("--recursive", action="store_true", help="Read input directory recursively.")
|
|
40
|
+
analyze_parser.add_argument("--pairs", help="Pair file for bond_mode=pairs; each line contains two water ids.")
|
|
41
|
+
analyze_parser.add_argument("--pair-id", choices=["resid", "oxygen_index", "atomid"], help="How ids in --pairs are interpreted.")
|
|
42
|
+
analyze_parser.add_argument("--n-jobs", default=None, help="Frame-level worker count for independent GRO/XYZ files; default auto runs serially.")
|
|
43
|
+
analyze_parser.add_argument("--strict", action="store_true", help="Stop on the first failed frame.")
|
|
44
|
+
analyze_parser.add_argument("--no-gro", action="store_true", help="Disable GRO structure output.")
|
|
45
|
+
analyze_parser.add_argument("--no-xlsx", action="store_true", help="Disable summary.xlsx output.")
|
|
46
|
+
return parser
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def main(argv: list[str] | None = None) -> int:
|
|
50
|
+
"""Dispatch the selected SQQ subcommand."""
|
|
51
|
+
args = build_parser().parse_args(argv)
|
|
52
|
+
if args.command == "init":
|
|
53
|
+
out = Path(args.output)
|
|
54
|
+
write_default_config(out)
|
|
55
|
+
print(f"Wrote default SQQ config: {out}")
|
|
56
|
+
return 0
|
|
57
|
+
if args.command == "analyze":
|
|
58
|
+
analyze(args)
|
|
59
|
+
return 0
|
|
60
|
+
raise AssertionError(f"Unhandled command: {args.command}")
|
|
61
|
+
|
|
62
|
+
|
sqq-0.1.0/sqq/config.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""Configuration defaults and YAML/JSON loading."""
|
|
4
|
+
|
|
5
|
+
from copy import deepcopy
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
import yaml
|
|
12
|
+
except ImportError: # pragma: no cover - exercised in minimal source-tree runs.
|
|
13
|
+
yaml = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Defaults are intentionally explicit so a run can be reproduced from
|
|
17
|
+
# run_config.yaml without relying on hidden command-line assumptions.
|
|
18
|
+
DEFAULT_CONFIG: dict[str, Any] = {
|
|
19
|
+
"input": {
|
|
20
|
+
"pattern": "*.gro",
|
|
21
|
+
"recursive": False,
|
|
22
|
+
"first_file_time_ps": 0.0,
|
|
23
|
+
"frame_time_step_ps": 100.0,
|
|
24
|
+
"xtc_stride": 1,
|
|
25
|
+
},
|
|
26
|
+
"water": {
|
|
27
|
+
"resnames": ["SOL", "TIP", "WAT", "HOH"],
|
|
28
|
+
"oxygen_names": ["OW", "O", "OH2"],
|
|
29
|
+
"hydrogen_names": ["HW1", "HW2", "H1", "H2", "HW", "HT1", "HT2"],
|
|
30
|
+
},
|
|
31
|
+
"guest": {
|
|
32
|
+
"resnames": ["CH4", "CO2", "MET", "ETH"],
|
|
33
|
+
"center_atoms": {"CH4": ["C"], "CO2": ["C"]},
|
|
34
|
+
"center_mode": "center_atom",
|
|
35
|
+
},
|
|
36
|
+
"graph": {
|
|
37
|
+
"bond_mode": "auto",
|
|
38
|
+
"oo_cutoff_nm": 0.35,
|
|
39
|
+
"hbond_distance_nm": 0.35,
|
|
40
|
+
"hbond_angle_deg": 30.0,
|
|
41
|
+
"pair_file": None,
|
|
42
|
+
"pair_id": "resid",
|
|
43
|
+
},
|
|
44
|
+
"pbc": {
|
|
45
|
+
"box_mode": "orthorhombic",
|
|
46
|
+
},
|
|
47
|
+
"ring": {
|
|
48
|
+
"sizes": [5, 6],
|
|
49
|
+
"primitive": True,
|
|
50
|
+
"chordless": True,
|
|
51
|
+
},
|
|
52
|
+
"cup": {
|
|
53
|
+
"mode": "general",
|
|
54
|
+
"enabled": True,
|
|
55
|
+
"base_sizes": "auto",
|
|
56
|
+
"side_sizes": "auto",
|
|
57
|
+
"max_combinations_per_base": 50000,
|
|
58
|
+
},
|
|
59
|
+
"cage": {
|
|
60
|
+
"ring_sizes": [5, 6],
|
|
61
|
+
"target_types": ["512", "51262", "51263", "51264"],
|
|
62
|
+
"output_other": False,
|
|
63
|
+
"other_max_faces": 20,
|
|
64
|
+
"enabled": True,
|
|
65
|
+
"search_mode": "grow",
|
|
66
|
+
"seed_mode": "ring",
|
|
67
|
+
"max_states_per_seed": 2000,
|
|
68
|
+
"max_total_states": 250000,
|
|
69
|
+
"occupancy_mode": "polyhedron",
|
|
70
|
+
"occupancy_radius_nm": 0.5,
|
|
71
|
+
},
|
|
72
|
+
"order": {
|
|
73
|
+
"f3f4_enabled": True,
|
|
74
|
+
"focus_waters": [],
|
|
75
|
+
},
|
|
76
|
+
"ice": {
|
|
77
|
+
"enabled": True,
|
|
78
|
+
"method": "chill",
|
|
79
|
+
"min_six_rings": 2,
|
|
80
|
+
"require_four_coord_neighbors": True,
|
|
81
|
+
},
|
|
82
|
+
"output": {
|
|
83
|
+
"write_gro": True,
|
|
84
|
+
"write_tsv": False,
|
|
85
|
+
"write_vmd": False,
|
|
86
|
+
"write_xlsx_summary": True,
|
|
87
|
+
"write_empty_files": False,
|
|
88
|
+
"gro_atom_mode": "full_water",
|
|
89
|
+
"center_resname": "CNT",
|
|
90
|
+
},
|
|
91
|
+
"parallel": {
|
|
92
|
+
"n_jobs": "auto",
|
|
93
|
+
},
|
|
94
|
+
"debug": {
|
|
95
|
+
"use_networkx_checks": False,
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def load_config(path: Path | None) -> dict[str, Any]:
|
|
101
|
+
"""Load a config file and merge it over built-in defaults."""
|
|
102
|
+
config = deepcopy(DEFAULT_CONFIG)
|
|
103
|
+
if path is None:
|
|
104
|
+
return config
|
|
105
|
+
with path.open("r", encoding="utf-8-sig") as handle:
|
|
106
|
+
text = handle.read()
|
|
107
|
+
if yaml is not None:
|
|
108
|
+
user_config = yaml.safe_load(text) or {}
|
|
109
|
+
else:
|
|
110
|
+
# Source-tree smoke tests can run without PyYAML; installed SQQ uses YAML.
|
|
111
|
+
try:
|
|
112
|
+
user_config = json.loads(text) if text.strip() else {}
|
|
113
|
+
except json.JSONDecodeError as exc:
|
|
114
|
+
raise RuntimeError("Reading YAML config files requires PyYAML. Install with `pip install -e .`.") from exc
|
|
115
|
+
if not isinstance(user_config, dict):
|
|
116
|
+
raise ValueError(f"Config file must contain a YAML mapping: {path}")
|
|
117
|
+
return merge_config(config, user_config)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def merge_config(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
|
|
121
|
+
"""Recursively merge user configuration into defaults."""
|
|
122
|
+
for key, value in override.items():
|
|
123
|
+
if isinstance(value, dict) and isinstance(base.get(key), dict):
|
|
124
|
+
merge_config(base[key], value)
|
|
125
|
+
else:
|
|
126
|
+
base[key] = value
|
|
127
|
+
return base
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def write_default_config(path: Path) -> None:
|
|
131
|
+
"""Write the default configuration template."""
|
|
132
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
133
|
+
with path.open("w", encoding="utf-8", newline="\n") as handle:
|
|
134
|
+
dump_config(DEFAULT_CONFIG, handle)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def dump_config(config: dict[str, Any], handle) -> None:
|
|
138
|
+
"""Write YAML when available, otherwise a JSON-compatible fallback."""
|
|
139
|
+
if yaml is not None:
|
|
140
|
+
yaml.safe_dump(config, handle, allow_unicode=True, sort_keys=False)
|
|
141
|
+
else:
|
|
142
|
+
json.dump(config, handle, ensure_ascii=False, indent=2)
|
|
143
|
+
handle.write("\n")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core SQQ topology algorithms."""
|