scgo 0.1.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 (235) hide show
  1. benchmark/benchmark_Pt.py +101 -0
  2. benchmark/benchmark_Pt_surface_graphite.py +122 -0
  3. benchmark/benchmark_common.py +673 -0
  4. docs/source/conf.py +109 -0
  5. examples/example_pt5_2oh_graphite.py +85 -0
  6. examples/example_pt5_gas.py +57 -0
  7. examples/example_pt5_graphite.py +69 -0
  8. examples/example_pt5_oh_gas.py +75 -0
  9. scgo/__init__.py +168 -0
  10. scgo/algorithms/__init__.py +26 -0
  11. scgo/algorithms/basinhopping_go.py +693 -0
  12. scgo/algorithms/ga_common.py +1455 -0
  13. scgo/algorithms/geneticalgorithm_go_torchsim.py +1553 -0
  14. scgo/algorithms/simple_go.py +138 -0
  15. scgo/ase_ga_patches/__init__.py +7 -0
  16. scgo/ase_ga_patches/_vector_utils.py +23 -0
  17. scgo/ase_ga_patches/cutandsplicepairing.py +726 -0
  18. scgo/ase_ga_patches/population.py +592 -0
  19. scgo/ase_ga_patches/standardmutations.py +1800 -0
  20. scgo/calculators/__init__.py +66 -0
  21. scgo/calculators/ase_batch_relaxer.py +50 -0
  22. scgo/calculators/mace_helpers.py +167 -0
  23. scgo/calculators/orca_helpers.py +128 -0
  24. scgo/calculators/torchsim_helpers.py +738 -0
  25. scgo/calculators/uma_helpers.py +77 -0
  26. scgo/calculators/vasp_helpers.py +111 -0
  27. scgo/cluster_adsorbate/__init__.py +49 -0
  28. scgo/cluster_adsorbate/combine.py +38 -0
  29. scgo/cluster_adsorbate/config.py +48 -0
  30. scgo/cluster_adsorbate/constraints.py +78 -0
  31. scgo/cluster_adsorbate/feasibility.py +129 -0
  32. scgo/cluster_adsorbate/geometry.py +124 -0
  33. scgo/cluster_adsorbate/hierarchical.py +215 -0
  34. scgo/cluster_adsorbate/placement.py +410 -0
  35. scgo/cluster_adsorbate/relax.py +222 -0
  36. scgo/cluster_adsorbate/reposition.py +139 -0
  37. scgo/cluster_adsorbate/rigid.py +105 -0
  38. scgo/cluster_adsorbate/validation.py +118 -0
  39. scgo/constants.py +30 -0
  40. scgo/database/__init__.py +175 -0
  41. scgo/database/cache.py +259 -0
  42. scgo/database/connection.py +180 -0
  43. scgo/database/constants.py +10 -0
  44. scgo/database/discovery.py +383 -0
  45. scgo/database/exceptions.py +9 -0
  46. scgo/database/health.py +165 -0
  47. scgo/database/helpers.py +948 -0
  48. scgo/database/manager.py +211 -0
  49. scgo/database/metadata.py +347 -0
  50. scgo/database/registry.py +254 -0
  51. scgo/database/schema.py +176 -0
  52. scgo/database/streaming.py +229 -0
  53. scgo/database/sync.py +208 -0
  54. scgo/database/transactions.py +51 -0
  55. scgo/exceptions.py +64 -0
  56. scgo/initialization/__init__.py +71 -0
  57. scgo/initialization/atomic_radii.py +193 -0
  58. scgo/initialization/candidate_discovery.py +285 -0
  59. scgo/initialization/geometry_helpers.py +1804 -0
  60. scgo/initialization/initialization_config.py +205 -0
  61. scgo/initialization/initializers.py +1395 -0
  62. scgo/initialization/random_spherical.py +1091 -0
  63. scgo/initialization/seed_combiners.py +238 -0
  64. scgo/initialization/steric_scoring.py +51 -0
  65. scgo/initialization/strategy_allocation.py +224 -0
  66. scgo/initialization/templates.py +1847 -0
  67. scgo/minima_search/__init__.py +10 -0
  68. scgo/minima_search/core.py +962 -0
  69. scgo/param_presets.py +569 -0
  70. scgo/runner_api.py +1511 -0
  71. scgo/surface/__init__.py +63 -0
  72. scgo/surface/composition.py +12 -0
  73. scgo/surface/config.py +161 -0
  74. scgo/surface/constraints.py +184 -0
  75. scgo/surface/deposition.py +618 -0
  76. scgo/surface/fragment_templates.py +39 -0
  77. scgo/surface/objectives.py +21 -0
  78. scgo/surface/pbc.py +53 -0
  79. scgo/surface/presets.py +108 -0
  80. scgo/surface/validation.py +434 -0
  81. scgo/system_types.py +658 -0
  82. scgo/ts_search/__init__.py +31 -0
  83. scgo/ts_search/parallel_neb.py +412 -0
  84. scgo/ts_search/transition_state.py +1479 -0
  85. scgo/ts_search/transition_state_io.py +571 -0
  86. scgo/ts_search/transition_state_run.py +936 -0
  87. scgo/ts_search/ts_network.py +708 -0
  88. scgo/ts_search/ts_statistics.py +42 -0
  89. scgo/utils/__init__.py +53 -0
  90. scgo/utils/atoms_helpers.py +21 -0
  91. scgo/utils/comparators.py +255 -0
  92. scgo/utils/diversity_scorer.py +188 -0
  93. scgo/utils/fitness_strategies.py +106 -0
  94. scgo/utils/helpers.py +806 -0
  95. scgo/utils/logging.py +121 -0
  96. scgo/utils/mlip_extras.py +42 -0
  97. scgo/utils/mutation_weights.py +377 -0
  98. scgo/utils/optimizer_utils.py +42 -0
  99. scgo/utils/parallel_workers.py +25 -0
  100. scgo/utils/rng_helpers.py +78 -0
  101. scgo/utils/run_helpers.py +530 -0
  102. scgo/utils/run_tracking.py +196 -0
  103. scgo/utils/runtime_warnings.py +22 -0
  104. scgo/utils/timing_report.py +82 -0
  105. scgo/utils/torchsim_policy.py +91 -0
  106. scgo/utils/ts_provenance.py +48 -0
  107. scgo/utils/ts_runner_kwargs.py +133 -0
  108. scgo/utils/validation.py +175 -0
  109. scgo-0.1.0.dist-info/METADATA +509 -0
  110. scgo-0.1.0.dist-info/RECORD +235 -0
  111. scgo-0.1.0.dist-info/WHEEL +5 -0
  112. scgo-0.1.0.dist-info/licenses/LICENSE +21 -0
  113. scgo-0.1.0.dist-info/top_level.txt +5 -0
  114. tests/__init__.py +0 -0
  115. tests/algorithms/__init__.py +0 -0
  116. tests/algorithms/test_adsorbate_ga_acceptance.py +210 -0
  117. tests/algorithms/test_adsorbate_operator_weights.py +111 -0
  118. tests/algorithms/test_algorithms_ga_common.py +50 -0
  119. tests/algorithms/test_core_adsorbate_ga_tags.py +151 -0
  120. tests/algorithms/test_edge_cases.py +300 -0
  121. tests/algorithms/test_ga_operator_acceptance.py +554 -0
  122. tests/algorithms/test_geneticalgorithm_generational.py +379 -0
  123. tests/algorithms/test_geneticalgorithm_logging.py +59 -0
  124. tests/algorithms/test_reproducibility.py +1014 -0
  125. tests/algorithms/test_validation.py +915 -0
  126. tests/ase_ga_patches/__init__.py +0 -0
  127. tests/ase_ga_patches/test_ase_ga_patches.py +476 -0
  128. tests/ase_ga_patches/test_ga_mutations.py +201 -0
  129. tests/ase_ga_patches/test_ga_pairing.py +160 -0
  130. tests/ase_ga_patches/test_population_selection.py +73 -0
  131. tests/ase_ga_patches/test_retry_reduction.py +560 -0
  132. tests/ase_ga_patches/test_surface_coherence.py +418 -0
  133. tests/benchmarks/__init__.py +0 -0
  134. tests/benchmarks/test_benchmarks.py +103 -0
  135. tests/calculators/__init__.py +0 -0
  136. tests/calculators/test_calculators.py +240 -0
  137. tests/calculators/test_torchsim_fixatoms_mapping.py +45 -0
  138. tests/calculators/test_torchsim_helpers.py +393 -0
  139. tests/calculators/test_uma_helpers.py +66 -0
  140. tests/cluster_adsorbate/test_fragment_reposition.py +83 -0
  141. tests/cluster_adsorbate/test_frozen_adsorbate_geometry.py +109 -0
  142. tests/cluster_adsorbate/test_general_adsorbate.py +172 -0
  143. tests/cluster_adsorbate/test_multi_fragment_placement.py +83 -0
  144. tests/cluster_adsorbate/test_multi_fragment_site_metadata.py +44 -0
  145. tests/cluster_adsorbate/test_oh_on_pt_cluster.py +137 -0
  146. tests/cluster_adsorbate/test_placement_heuristics.py +70 -0
  147. tests/cluster_adsorbate/test_site_diversity.py +81 -0
  148. tests/conftest.py +253 -0
  149. tests/constants.py +41 -0
  150. tests/database/__init__.py +0 -0
  151. tests/database/test_database_core.py +1316 -0
  152. tests/database/test_database_metadata_adapter.py +93 -0
  153. tests/database/test_initialization_cache.py +105 -0
  154. tests/database/test_mark_final_minima.py +125 -0
  155. tests/database/test_mark_final_minima_dbpaths.py +60 -0
  156. tests/database/test_parallel_worker_ase_compat.py +45 -0
  157. tests/database/test_persist_provenance.py +34 -0
  158. tests/database/test_registry.py +231 -0
  159. tests/database/test_require_json1.py +29 -0
  160. tests/database/test_schema_utils.py +86 -0
  161. tests/initialization/__init__.py +0 -0
  162. tests/initialization/test_atomic_radii.py +59 -0
  163. tests/initialization/test_atomic_radii_blmin.py +23 -0
  164. tests/initialization/test_batch_initialization.py +513 -0
  165. tests/initialization/test_composition_matching.py +103 -0
  166. tests/initialization/test_connectivity.py +328 -0
  167. tests/initialization/test_geometry_helpers.py +709 -0
  168. tests/initialization/test_init_canonical_mtime.py +68 -0
  169. tests/initialization/test_init_common.py +1559 -0
  170. tests/initialization/test_init_logging.py +27 -0
  171. tests/initialization/test_init_random_spherical.py +249 -0
  172. tests/initialization/test_init_seed_growth.py +630 -0
  173. tests/initialization/test_init_smart.py +470 -0
  174. tests/initialization/test_init_template.py +333 -0
  175. tests/initialization/test_initialization_modes.py +312 -0
  176. tests/initialization/test_mixed_compositions.py +136 -0
  177. tests/initialization/test_parameter_sensitivity.py +335 -0
  178. tests/initialization/test_path_prefilter.py +27 -0
  179. tests/initialization/test_seed_combiners.py +395 -0
  180. tests/initialization/test_template_discovery_logs.py +41 -0
  181. tests/initialization/test_template_facet_vertex.py +193 -0
  182. tests/initialization/test_templates.py +753 -0
  183. tests/integration/__init__.py +0 -0
  184. tests/integration/test_integration.py +759 -0
  185. tests/integration/test_main_final_tagging.py +177 -0
  186. tests/integration/test_run_api.py +1009 -0
  187. tests/integration/test_run_go_surface.py +65 -0
  188. tests/integration/test_runners_emulation.py +70 -0
  189. tests/minima_search/__init__.py +0 -0
  190. tests/minima_search/test_minima_search.py +875 -0
  191. tests/minima_search/test_output.py +485 -0
  192. tests/minima_search/test_run_tracking.py +511 -0
  193. tests/param_presets/__init__.py +0 -0
  194. tests/param_presets/test_param_presets.py +367 -0
  195. tests/param_presets/test_param_presets_and_run_helpers.py +501 -0
  196. tests/surface/__init__.py +1 -0
  197. tests/surface/test_hierarchical_deposition.py +189 -0
  198. tests/surface/test_mobile_symbol_validation.py +107 -0
  199. tests/surface/test_slab_ga_metadata.py +42 -0
  200. tests/surface/test_slab_ordering_contract.py +125 -0
  201. tests/surface/test_slab_pbc.py +49 -0
  202. tests/surface/test_supported_cluster_binding.py +355 -0
  203. tests/surface/test_surface_constraints.py +197 -0
  204. tests/surface/test_surface_deposition.py +324 -0
  205. tests/surface/test_surface_ga_smoke.py +51 -0
  206. tests/surface/test_surface_ga_torchsim.py +156 -0
  207. tests/test_optimization_algorithm_select.py +19 -0
  208. tests/test_optional_extras_smoke.py +17 -0
  209. tests/test_runner_surface.py +85 -0
  210. tests/test_utils.py +780 -0
  211. tests/ts_search/__init__.py +0 -0
  212. tests/ts_search/test_neb_blockwise_alignment.py +94 -0
  213. tests/ts_search/test_parallel_neb.py +292 -0
  214. tests/ts_search/test_surface_neb_alignment.py +500 -0
  215. tests/ts_search/test_ts_final_minima_integration.py +212 -0
  216. tests/ts_search/test_ts_integration.py +1001 -0
  217. tests/ts_search/test_ts_integration_cu4_mace.py +564 -0
  218. tests/ts_search/test_ts_interpolation_mic.py +212 -0
  219. tests/ts_search/test_ts_network.py +395 -0
  220. tests/ts_search/test_ts_postprocessing.py +964 -0
  221. tests/ts_search/test_ts_robustness.py +306 -0
  222. tests/ts_search/test_ts_search.py +1027 -0
  223. tests/ts_search/test_ts_search_forces_failures.py +69 -0
  224. tests/utils/__init__.py +0 -0
  225. tests/utils/test_atoms_helpers.py +115 -0
  226. tests/utils/test_diversity_scorer.py +168 -0
  227. tests/utils/test_fitness_strategies.py +237 -0
  228. tests/utils/test_helpers.py +492 -0
  229. tests/utils/test_is_true_minimum.py +335 -0
  230. tests/utils/test_logging_trace_method.py +24 -0
  231. tests/utils/test_mutation_weights.py +233 -0
  232. tests/utils/test_optimizer_utils.py +90 -0
  233. tests/utils/test_rng_helpers.py +208 -0
  234. tests/utils/test_torchsim_policy.py +117 -0
  235. tests/utils/test_verbosity.py +247 -0
@@ -0,0 +1,101 @@
1
+ """Benchmark suite for platinum clusters based on reference structures.
2
+
3
+ The utilities here drive SCGO against a curated Pt benchmark set and evaluate
4
+ the recovered minima primarily through geometric agreement and, secondarily,
5
+ relative energetic ordering. The script doubles as a pytest entry point and a
6
+ standalone CLI for rapid regression checks while tweaking optimization knobs.
7
+
8
+ Campaign outputs are written under
9
+ ``benchmark/results/<formula>_<backend>_<model>/`` (for example:
10
+ ``pt5_mace_mace_matpes_0`` or ``pt5_uma_uma-s-1p2-oc25``).
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ import os
17
+ import time
18
+
19
+ import pytest
20
+
21
+ from benchmark.benchmark_common import (
22
+ DEFAULT_CLUSTERS,
23
+ MIN_RECOVERY_RATE,
24
+ NUM_GROUND_TRUTH,
25
+ add_common_benchmark_cli,
26
+ evaluate_cluster,
27
+ get_benchmark_params,
28
+ run_benchmark_suite,
29
+ )
30
+ from scgo.utils.logging import get_logger
31
+
32
+ BENCHMARK_SEEDS = [42, 43, 44, 45]
33
+ MODEL_NAME: str | None = None
34
+ BENCHMARK_BACKEND = os.environ.get("SCGO_BENCHMARK_BACKEND", "mace")
35
+ logger = get_logger(__name__)
36
+
37
+
38
+ @pytest.mark.parametrize(
39
+ "cluster_formula, seed",
40
+ [(c, s) for c in DEFAULT_CLUSTERS for s in BENCHMARK_SEEDS],
41
+ )
42
+ def test_benchmark_minima_recovery(cluster_formula: str, seed: int):
43
+ """Pytest entry point for validating a single cluster benchmark run."""
44
+ params = get_benchmark_params(
45
+ seed, model_name=MODEL_NAME, backend=BENCHMARK_BACKEND
46
+ )
47
+ result = evaluate_cluster(
48
+ cluster_formula,
49
+ params=params,
50
+ seed=seed,
51
+ comparator_tolerance=0.05,
52
+ num_ground_truth=NUM_GROUND_TRUTH,
53
+ verbose=True,
54
+ )
55
+
56
+ if result.skipped:
57
+ pytest.skip(result.skip_reason or "Benchmark skipped")
58
+
59
+ if not result.matched_indices:
60
+ pytest.skip(
61
+ f"No minima recovered for {cluster_formula}. Check optimizer settings.",
62
+ )
63
+
64
+ if result.recovery_rate < MIN_RECOVERY_RATE:
65
+ pytest.xfail(
66
+ f"Recovery rate {result.recovery_rate:.2f} below threshold {MIN_RECOVERY_RATE:.2f}.",
67
+ )
68
+
69
+
70
+ def main() -> None:
71
+ """CLI entry point for running the Pt benchmark suite."""
72
+ parser = argparse.ArgumentParser(
73
+ description="Pt cluster geometric recovery benchmark (MACE/TorchSim or UMA/ASE GA).",
74
+ )
75
+ add_common_benchmark_cli(parser)
76
+ args = parser.parse_args()
77
+
78
+ params = get_benchmark_params(
79
+ args.seed,
80
+ model_name=args.model_name,
81
+ backend=args.backend,
82
+ uma_task=args.uma_task,
83
+ )
84
+ params["optimizer_params"]["ga"]["niter"] = args.niter
85
+ params["optimizer_params"]["ga"]["population_size"] = args.population_size
86
+
87
+ t0 = time.perf_counter()
88
+ run_benchmark_suite(
89
+ clusters=args.clusters,
90
+ seed=args.seed,
91
+ params=params,
92
+ verbose=True,
93
+ backend=args.backend,
94
+ uma_task=args.uma_task,
95
+ )
96
+ elapsed = time.perf_counter() - t0
97
+ logger.info("Benchmark wall time: %.1f s (%s)", elapsed, args.backend)
98
+
99
+
100
+ if __name__ == "__main__":
101
+ main()
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env python3
2
+ """Benchmark Pt cluster search on graphite with top-layer slab relaxation.
3
+
4
+ Mirrors ``benchmark/benchmark_Pt.py`` for a surface system: sweeps Pt cluster
5
+ sizes with one seed, runs SCGO over the range, and logs per-size minima from
6
+ the campaign. Outputs live under ``benchmark/results/pt_surface_graphite/`` (same
7
+ layout as gas-phase benchmarks: ``<Formula>_searches`` per size). See
8
+ ``benchmark.benchmark_common.PT_SURFACE_GRAPHITE_RESULTS_DIR``.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import time
15
+
16
+ from benchmark.benchmark_common import (
17
+ DEFAULT_CLUSTERS,
18
+ PT_SURFACE_GRAPHITE_RESULTS_DIR,
19
+ add_common_benchmark_cli,
20
+ apply_ga_benchmark_overrides,
21
+ format_ga_profile_lines,
22
+ get_benchmark_params,
23
+ load_latest_ga_profile,
24
+ parse_atom_count,
25
+ )
26
+ from scgo.runner_api import run_go_campaign
27
+ from scgo.surface import (
28
+ DEFAULT_GRAPHITE_SLAB_LAYERS,
29
+ DEFAULT_GRAPHITE_SLAB_REPEAT_XY,
30
+ make_graphite_surface_config,
31
+ )
32
+ from scgo.utils.helpers import get_cluster_formula
33
+ from scgo.utils.logging import get_logger
34
+
35
+ DEFAULT_OUTPUT_ROOT = PT_SURFACE_GRAPHITE_RESULTS_DIR.resolve()
36
+
37
+ logger = get_logger(__name__)
38
+
39
+
40
+ def parse_args() -> argparse.Namespace:
41
+ parser = argparse.ArgumentParser(
42
+ description=(
43
+ "Run Pt-on-graphite SCGO benchmark sweep with top-layer slab relaxation."
44
+ )
45
+ )
46
+ add_common_benchmark_cli(parser)
47
+ parser.set_defaults(niter=6, population_size=24)
48
+ parser.add_argument("--slab-layers", type=int, default=DEFAULT_GRAPHITE_SLAB_LAYERS)
49
+ parser.add_argument(
50
+ "--slab-repeat-xy",
51
+ type=int,
52
+ default=DEFAULT_GRAPHITE_SLAB_REPEAT_XY,
53
+ help="In-plane supercell repeats; default is large enough for Pt4-Pt11 adsorption.",
54
+ )
55
+ return parser.parse_args()
56
+
57
+
58
+ def main() -> None:
59
+ args = parse_args()
60
+ output_root = DEFAULT_OUTPUT_ROOT
61
+ output_root.mkdir(parents=True, exist_ok=True)
62
+ clusters = args.clusters or DEFAULT_CLUSTERS
63
+
64
+ surface_config = make_graphite_surface_config(
65
+ slab_layers=args.slab_layers,
66
+ slab_repeat_xy=args.slab_repeat_xy,
67
+ )
68
+
69
+ base_params = get_benchmark_params(
70
+ args.seed,
71
+ model_name=args.model_name,
72
+ backend=args.backend,
73
+ uma_task=args.uma_task,
74
+ )
75
+ params = apply_ga_benchmark_overrides(
76
+ base_params,
77
+ niter=args.niter,
78
+ population_size=args.population_size,
79
+ surface_config=surface_config,
80
+ n_jobs_population_init=-2,
81
+ batch_size=4,
82
+ )
83
+
84
+ t0 = time.perf_counter()
85
+
86
+ logger.info("Per-size summary:")
87
+ total_minima = 0
88
+ for formula in clusters:
89
+ n_atoms = parse_atom_count(formula)
90
+ formula = get_cluster_formula(["Pt"] * n_atoms)
91
+ results = run_go_campaign(
92
+ [["Pt"] * n_atoms],
93
+ params=params,
94
+ seed=args.seed,
95
+ output_dir=output_root,
96
+ surface_config=surface_config,
97
+ system_type="surface_cluster",
98
+ )
99
+ minima = results.get(formula, [])
100
+ n_found = len(minima)
101
+ total_minima += n_found
102
+ if n_found == 0:
103
+ logger.info(" %s: 0 minima", formula)
104
+ continue
105
+ best_energy = minima[0][0]
106
+ logger.info(" %s: %d minima, best E=%.6f eV", formula, n_found, best_energy)
107
+ profile = load_latest_ga_profile(output_root, formula)
108
+ if profile:
109
+ for line in format_ga_profile_lines(profile, detailed=True, max_entries=8):
110
+ logger.info(" %s", line)
111
+
112
+ logger.info(
113
+ "Finished benchmark. Total minima saved across formulas: %d under %s",
114
+ total_minima,
115
+ output_root,
116
+ )
117
+ elapsed = time.perf_counter() - t0
118
+ logger.info("Benchmark wall time: %.1f s (%s)", elapsed, args.backend)
119
+
120
+
121
+ if __name__ == "__main__":
122
+ main()