adaptivepy-sampling 0.1.1__tar.gz → 0.2.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 (48) hide show
  1. adaptivepy_sampling-0.2.0/LICENSE +21 -0
  2. adaptivepy_sampling-0.2.0/PKG-INFO +136 -0
  3. adaptivepy_sampling-0.2.0/README.md +92 -0
  4. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/__init__.py +1 -1
  5. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/api.py +40 -9
  6. adaptivepy_sampling-0.2.0/adaptivepy/config/schema.py +497 -0
  7. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/io/__init__.py +4 -0
  8. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/io/loader.py +68 -9
  9. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/output/writer.py +110 -0
  10. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/policies/__init__.py +2 -0
  11. adaptivepy_sampling-0.2.0/adaptivepy/policies/fast.py +296 -0
  12. adaptivepy_sampling-0.2.0/adaptivepy/policies/ma_reap.py +430 -0
  13. adaptivepy_sampling-0.2.0/adaptivepy_sampling.egg-info/PKG-INFO +136 -0
  14. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy_sampling.egg-info/SOURCES.txt +3 -0
  15. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy_sampling.egg-info/requires.txt +5 -0
  16. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/pyproject.toml +8 -3
  17. adaptivepy_sampling-0.2.0/tests/test_adaptivepy.py +505 -0
  18. adaptivepy_sampling-0.1.1/PKG-INFO +0 -52
  19. adaptivepy_sampling-0.1.1/README.md +0 -35
  20. adaptivepy_sampling-0.1.1/adaptivepy/config/schema.py +0 -196
  21. adaptivepy_sampling-0.1.1/adaptivepy_sampling.egg-info/PKG-INFO +0 -52
  22. adaptivepy_sampling-0.1.1/tests/test_adaptivepy.py +0 -77
  23. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/cli/__init__.py +0 -0
  24. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/cli/run.py +0 -0
  25. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/clustering/__init__.py +0 -0
  26. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/clustering/base.py +0 -0
  27. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/clustering/regular_space.py +0 -0
  28. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/clustering/sklearn_kmeans.py +0 -0
  29. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/clustering/sklearn_minibatch.py +0 -0
  30. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/config/__init__.py +0 -0
  31. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/io/trajectory.py +0 -0
  32. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/models.py +0 -0
  33. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/output/__init__.py +0 -0
  34. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/output/pdb_writer.py +0 -0
  35. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/policies/base.py +0 -0
  36. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/policies/least_counts.py +0 -0
  37. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/policies/random.py +0 -0
  38. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/selection/__init__.py +0 -0
  39. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/selection/frame_selector.py +0 -0
  40. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/stats/__init__.py +0 -0
  41. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/stats/cluster_stats.py +0 -0
  42. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/utils/__init__.py +0 -0
  43. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/utils/io_utils.py +0 -0
  44. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy/utils/logging.py +0 -0
  45. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy_sampling.egg-info/dependency_links.txt +0 -0
  46. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy_sampling.egg-info/entry_points.txt +0 -0
  47. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/adaptivepy_sampling.egg-info/top_level.txt +0 -0
  48. {adaptivepy_sampling-0.1.1 → adaptivepy_sampling-0.2.0}/setup.cfg +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hassan
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.
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.4
2
+ Name: adaptivepy-sampling
3
+ Version: 0.2.0
4
+ Summary: Adaptive sampling on MD trajectories via clustering and policy-driven seed selection
5
+ Author: Hassan
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Hassan
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Requires-Python: >=3.9
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: numpy>=1.20
32
+ Requires-Dist: scikit-learn>=1.0
33
+ Requires-Dist: pyyaml>=6.0
34
+ Requires-Dist: click>=8.0
35
+ Requires-Dist: joblib>=1.0
36
+ Requires-Dist: mdtraj>=1.9
37
+ Requires-Dist: scipy>=1.7
38
+ Provides-Extra: dev
39
+ Requires-Dist: pytest>=7.0; extra == "dev"
40
+ Provides-Extra: docs
41
+ Requires-Dist: mkdocs-material>=9.0; extra == "docs"
42
+ Requires-Dist: mkdocstrings[python]>=0.24; extra == "docs"
43
+ Dynamic: license-file
44
+
45
+ # AdaptivePy
46
+
47
+ **Adaptive sampling for molecular dynamics trajectories**
48
+
49
+ Clustering-based state space partitioning and policy-driven seed selection for MD workflows.
50
+
51
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue?style=for-the-badge)](https://hnadeem2.github.io/AdaptivePy/)
52
+ [![PyPI](https://img.shields.io/badge/PyPI-adaptivepy--sampling-orange?style=for-the-badge)](https://pypi.org/project/adaptivepy-sampling/)
53
+ [![Python](https://img.shields.io/badge/python-3.9+-green?style=for-the-badge)](https://www.python.org/)
54
+
55
+ ---
56
+
57
+ ## Overview
58
+
59
+ AdaptivePy helps you identify under-sampled regions of conformational space and select seed frames for new simulations. It loads per-trajectory feature arrays, clusters frames, applies adaptive policies, and writes reproducible metadata and optional PDB structures.
60
+
61
+ **Full documentation:** [https://hnadeem2.github.io/AdaptivePy/](https://hnadeem2.github.io/AdaptivePy/)
62
+
63
+ | | |
64
+ |---|---|
65
+ | **Input** | Feature arrays (`.npy` / `.pkl`), optional coordinate trajectories |
66
+ | **Clustering** | KMeans, MiniBatch KMeans, regular-space |
67
+ | **Policies** | Least counts, random, FAST, MA-REAP (extensible) |
68
+ | **Output** | Seeds, cluster assignments, model, logs, optional PDBs |
69
+
70
+ ## Installation
71
+
72
+ ```bash
73
+ pip install adaptivepy-sampling
74
+ ```
75
+
76
+ For development:
77
+
78
+ ```bash
79
+ git clone https://github.com/hnadeem2/AdaptivePy.git
80
+ cd AdaptivePy
81
+ pip install -e ".[dev,docs]"
82
+ ```
83
+
84
+ ## Quick start
85
+
86
+ 1. **Prepare features** — one file per trajectory, shape `(n_frames, n_features)`:
87
+
88
+ ```text
89
+ features/
90
+ ├── traj_0.npy
91
+ └── traj_1.pkl
92
+ ```
93
+
94
+ 2. **Configure** — edit `examples/config.yaml` (or create your own).
95
+
96
+ 3. **Run**:
97
+
98
+ ```bash
99
+ adaptivepy run examples/config.yaml
100
+ ```
101
+
102
+ See the [Getting Started guide](https://hnadeem2.github.io/AdaptivePy/getting-started/) for a complete walkthrough.
103
+
104
+ ## CLI
105
+
106
+ ```bash
107
+ adaptivepy run config.yaml # run adaptive sampling
108
+ adaptivepy validate config.yaml # validate inputs only
109
+ adaptivepy list-policies # list available policies
110
+ ```
111
+
112
+ ## Python API
113
+
114
+ ```python
115
+ from adaptivepy import run_adaptive_sampling
116
+
117
+ results = run_adaptive_sampling("config.yaml")
118
+ ```
119
+
120
+ ## Documentation
121
+
122
+ | Guide | Description |
123
+ |-------|-------------|
124
+ | [Getting Started](https://hnadeem2.github.io/AdaptivePy/getting-started/) | First run in minutes |
125
+ | [Configuration](https://hnadeem2.github.io/AdaptivePy/configuration/) | YAML options and defaults |
126
+ | [Feature Inputs](https://hnadeem2.github.io/AdaptivePy/features/) | File formats and layout |
127
+ | [Policies](https://hnadeem2.github.io/AdaptivePy/policies/) | Seed selection strategies |
128
+ | [API Reference](https://hnadeem2.github.io/AdaptivePy/reference/api/) | Module documentation |
129
+
130
+ ## Contributors
131
+
132
+ - Hassan
133
+
134
+ ## License
135
+
136
+ MIT. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,92 @@
1
+ # AdaptivePy
2
+
3
+ **Adaptive sampling for molecular dynamics trajectories**
4
+
5
+ Clustering-based state space partitioning and policy-driven seed selection for MD workflows.
6
+
7
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue?style=for-the-badge)](https://hnadeem2.github.io/AdaptivePy/)
8
+ [![PyPI](https://img.shields.io/badge/PyPI-adaptivepy--sampling-orange?style=for-the-badge)](https://pypi.org/project/adaptivepy-sampling/)
9
+ [![Python](https://img.shields.io/badge/python-3.9+-green?style=for-the-badge)](https://www.python.org/)
10
+
11
+ ---
12
+
13
+ ## Overview
14
+
15
+ AdaptivePy helps you identify under-sampled regions of conformational space and select seed frames for new simulations. It loads per-trajectory feature arrays, clusters frames, applies adaptive policies, and writes reproducible metadata and optional PDB structures.
16
+
17
+ **Full documentation:** [https://hnadeem2.github.io/AdaptivePy/](https://hnadeem2.github.io/AdaptivePy/)
18
+
19
+ | | |
20
+ |---|---|
21
+ | **Input** | Feature arrays (`.npy` / `.pkl`), optional coordinate trajectories |
22
+ | **Clustering** | KMeans, MiniBatch KMeans, regular-space |
23
+ | **Policies** | Least counts, random, FAST, MA-REAP (extensible) |
24
+ | **Output** | Seeds, cluster assignments, model, logs, optional PDBs |
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pip install adaptivepy-sampling
30
+ ```
31
+
32
+ For development:
33
+
34
+ ```bash
35
+ git clone https://github.com/hnadeem2/AdaptivePy.git
36
+ cd AdaptivePy
37
+ pip install -e ".[dev,docs]"
38
+ ```
39
+
40
+ ## Quick start
41
+
42
+ 1. **Prepare features** — one file per trajectory, shape `(n_frames, n_features)`:
43
+
44
+ ```text
45
+ features/
46
+ ├── traj_0.npy
47
+ └── traj_1.pkl
48
+ ```
49
+
50
+ 2. **Configure** — edit `examples/config.yaml` (or create your own).
51
+
52
+ 3. **Run**:
53
+
54
+ ```bash
55
+ adaptivepy run examples/config.yaml
56
+ ```
57
+
58
+ See the [Getting Started guide](https://hnadeem2.github.io/AdaptivePy/getting-started/) for a complete walkthrough.
59
+
60
+ ## CLI
61
+
62
+ ```bash
63
+ adaptivepy run config.yaml # run adaptive sampling
64
+ adaptivepy validate config.yaml # validate inputs only
65
+ adaptivepy list-policies # list available policies
66
+ ```
67
+
68
+ ## Python API
69
+
70
+ ```python
71
+ from adaptivepy import run_adaptive_sampling
72
+
73
+ results = run_adaptive_sampling("config.yaml")
74
+ ```
75
+
76
+ ## Documentation
77
+
78
+ | Guide | Description |
79
+ |-------|-------------|
80
+ | [Getting Started](https://hnadeem2.github.io/AdaptivePy/getting-started/) | First run in minutes |
81
+ | [Configuration](https://hnadeem2.github.io/AdaptivePy/configuration/) | YAML options and defaults |
82
+ | [Feature Inputs](https://hnadeem2.github.io/AdaptivePy/features/) | File formats and layout |
83
+ | [Policies](https://hnadeem2.github.io/AdaptivePy/policies/) | Seed selection strategies |
84
+ | [API Reference](https://hnadeem2.github.io/AdaptivePy/reference/api/) | Module documentation |
85
+
86
+ ## Contributors
87
+
88
+ - Hassan
89
+
90
+ ## License
91
+
92
+ MIT. See [LICENSE](LICENSE) for details.
@@ -1,6 +1,6 @@
1
1
  """AdaptivePy: adaptive sampling for molecular dynamics trajectories."""
2
2
 
3
- __version__ = "0.1.1"
3
+ __version__ = "0.2.0"
4
4
 
5
5
  from adaptivepy.api import run_adaptive_sampling
6
6
 
@@ -9,8 +9,9 @@ from typing import Dict, List, Optional
9
9
  import numpy as np
10
10
 
11
11
  from adaptivepy.clustering import create_clusterer, fit_clusterer
12
- from adaptivepy.config.schema import RunConfig, load_config
12
+ from adaptivepy.config.schema import RunConfig, build_policy_kwargs, load_config
13
13
  from adaptivepy.io.loader import (
14
+ list_feature_files,
14
15
  list_trajectory_files,
15
16
  load_features,
16
17
  validate_dataset,
@@ -27,6 +28,8 @@ from adaptivepy.output.writer import (
27
28
  write_cluster_model,
28
29
  write_cluster_statistics,
29
30
  write_combined_metadata,
31
+ write_fast_scores,
32
+ write_ma_reap_outputs,
30
33
  write_policy_outputs,
31
34
  write_run_config,
32
35
  )
@@ -84,7 +87,7 @@ def run_adaptive_sampling(
84
87
  np.random.seed(config.random_seed)
85
88
 
86
89
  # --- Load and validate data ---
87
- feature_files = sorted(Path(config.features_dir).glob("*.npy"))
90
+ feature_files = list_feature_files(config.features_dir)
88
91
  trajectory_files: Optional[List[Path]] = None
89
92
  trajectory_map: Optional[Dict[int, Path]] = None
90
93
 
@@ -120,6 +123,7 @@ def run_adaptive_sampling(
120
123
 
121
124
  cluster_stats = compute_cluster_stats(dataset)
122
125
  centers = clusterer.cluster_centers_
126
+ n_features = dataset.feature_matrix.shape[1]
123
127
 
124
128
  logger.info(
125
129
  "Clustering complete: %d clusters, %d total frames",
@@ -138,9 +142,15 @@ def run_adaptive_sampling(
138
142
 
139
143
  for policy_name in config.policies:
140
144
  logger.info("Applying policy: %s", policy_name)
141
- policy_kwargs = {}
142
- if policy_name == "random":
143
- policy_kwargs["random_state"] = config.random_seed
145
+ policy_kwargs = build_policy_kwargs(
146
+ policy_name,
147
+ config,
148
+ n_features=n_features,
149
+ traj_names=dataset.traj_names,
150
+ n_clusters=len(cluster_stats),
151
+ )
152
+ if policy_name == "ma_reap":
153
+ policy_kwargs["cluster_centers"] = centers
144
154
 
145
155
  policy = get_policy(policy_name, **policy_kwargs)
146
156
  selected_clusters = policy.select_clusters(
@@ -160,6 +170,20 @@ def run_adaptive_sampling(
160
170
  policy_name, seeds, cluster_stats, output_dir
161
171
  )
162
172
 
173
+ if policy_name == "fast" and hasattr(policy, "last_scores"):
174
+ write_fast_scores(policy.last_scores, policy_dir)
175
+
176
+ if policy_name == "ma_reap" and hasattr(policy, "last_scores"):
177
+ write_ma_reap_outputs(
178
+ scores=policy.last_scores,
179
+ weights=policy.last_weights,
180
+ stakes=policy.last_stakes,
181
+ executors=policy.last_executors,
182
+ agent_names=policy.agent_names,
183
+ seeds=seeds,
184
+ output_dir=policy_dir,
185
+ )
186
+
163
187
  if (
164
188
  config.write_pdbs
165
189
  and trajectory_map is not None
@@ -199,9 +223,7 @@ def validate_config(config_path: str | Path) -> RunConfig:
199
223
  config_path = Path(config_path)
200
224
  config = load_config(config_path)
201
225
 
202
- feature_files = sorted(Path(config.features_dir).glob("*.npy"))
203
- if not feature_files:
204
- raise ValueError(f"No feature files in {config.features_dir}")
226
+ feature_files = list_feature_files(config.features_dir)
205
227
 
206
228
  trajectory_files = None
207
229
  if config.trajectories_dir is not None:
@@ -210,6 +232,7 @@ def validate_config(config_path: str | Path) -> RunConfig:
210
232
 
211
233
  dataset = load_features(config.features_dir)
212
234
  validate_dataset(dataset, trajectory_files)
235
+ n_features = dataset.feature_matrix.shape[1]
213
236
 
214
237
  if config.trajectories_dir is not None and config.topology is not None:
215
238
  trajectory_map = build_trajectory_map(
@@ -224,6 +247,14 @@ def validate_config(config_path: str | Path) -> RunConfig:
224
247
  )
225
248
 
226
249
  for policy_name in config.policies:
227
- get_policy(policy_name)
250
+ get_policy(
251
+ policy_name,
252
+ **build_policy_kwargs(
253
+ policy_name,
254
+ config,
255
+ n_features=n_features,
256
+ traj_names=dataset.traj_names,
257
+ ),
258
+ )
228
259
 
229
260
  return config